Lately I've been asked about doing FTP related stuff in .NET .
There appear to be many "Ftp Clients" out there on CodeProject and other sites.
I really don't get 'em.
They are simple a leaky abstraction on top of straightforward BCL classes.
So what my solution is?
1: public void Upload(string server, int port, string targetFolder, string fileName, string username, string password, bool isActive)
2: {
3: var url = string.Format(
4: "ftp://{0}:{1}{2}/{3}", server, port, targetFolder, fileName)
5: using (var ftp = (FtpWebRequest)WebRequest.Create(url))
6: {
7: ftp.Credentials = new NetworkCredential(username, password);
8: ftp.KeepAlive = false;
9: ftp.UseBinary = true;
10: ftp.Method = WebRequestMethods.Ftp.UploadFile;
11: if (isActive)
12: ftp.UsePassive = false;
13:
14: using (var writer = new BinaryWriter(ftp.GetRequestStream()))
15: writer.Write(File.ReadAllBytes(fileName));
16: }
17: }
This basic notepad code covers most of the functionality in FtpWebRequest. You can easily set Binary/ASCII, Active/Passive, Credentials and whatnot.
Alternatively, in some cases you can just spawn a ftp.exe process with a simple ftp script. Anyway you can rid yourself from unneeded leaky abstractions.
Following Scott Hanselman's post on FileUpload in ASP.NET MVC, I'll add here a few bits on doing that in MonoRail.
First, as MonoRail is an extension on top of plain ol' ASP.NET, just as ASP.NET MVC is, you can do the exact same thing - i.e iterate over Request.Files, and use a mocked Files collection for test or something.
But as the action parameters binder is very smart, and easily extensible, it's even nicer to just bind the posted data to a HttpPostedFile, using a FileBinder:
1: [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
2: public class FileBinderAttribute: Attribute, IParameterBinder
3: {
4: public int CalculateParamPoints(IEngineContext context, IController controller, IControllerContext controllerContext, ParameterInfo parameterInfo)
5: {
6: var key = parameterInfo.Name;
7: return context.Request.Files[key] != null ? 10 : 0;
8: }
9:
10: public object Bind(IEngineContext context, IController controller, IControllerContext controllerContext, ParameterInfo parameterInfo)
11: {
12: var key = parameterInfo.Name;
13: return context.Request.Files[key] as HttpPostedFile;
14: }
15: }
So a custom binder is an attribute, that implements IParameterBinder, a two methods interface:
so now you're action can look like this:
1: public void Save([FileBinder] HttpPostedFile myfile)
2: {
3: if (myFile != null)
4: {
5: // do stuff with the file
6: }
7: }
Cool? well actually what really is cool is that binding to HttpPostedFile is baked into MonoRail to begin with - so you don't even need this FileBinderAttribute at all ! you can simply
1: public void Save(HttpPostedFile myfile)
2: {
3: if (myFile != null)
4: {
5: // do stuff with the file
6: }
7: }
So why did I show you that?
Testablility.
Since HttpPostedFile is not easily mockable* (cuz it's bloody sealed and not new-able), you should do what you always do when in need to bypass one of these un-testable hard-to-test* sealed classes: Adapter pattern. Introduce IHttpPostedFile, and supply your own HttpPostedFile encapsulating the built in one.
so:
1: [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
2: public class FileBinderAttribute: Attribute, IParameterBinder
3: {
4: public int CalculateParamPoints(IEngineContext context, IController controller, IControllerContext controllerContext, ParameterInfo parameterInfo)
5: {
6: var key = parameterInfo.Name;
7: return context.Request.Files[key] != null ? 10 : 0;
8: }
9:
10: public object Bind(IEngineContext context, IController controller, IControllerContext controllerContext, ParameterInfo parameterInfo)
11: {
12: var key = parameterInfo.Name;13: var file = context.Request.Files[key] as HttpPostedFile;
14: return file == null ? null : HttpPostedFileAdapter(file);
15: }
16: }
and
1: public void Save([FileBinder] IHttpPostedFile myfile)
2: {
3: if (myFile != null)
4: {
5: // do stuff with the file
6: }
7: }
* Yes Roy, I know you can throw some TypeMock magic at it
DISCLAIMER:
If you are a potential client of mine, or rather a current one, please stop reading NOW, as it's one of these embarrassing "I am sometimes too stupid" posts.
Oh my.
That's how my 3am code can look like:
1: var page = filter.Page.GetValueOrDefault(1);
2: var pageSize = filter.PageSize.GetValueOrDefault(30);
3: var firstResult = (page - 1) + pageSize;
It's for NHibernate style paging (i.e. firstResult is for a 0 based index)
Spotted (thanks to DbAwareIntegrationTests) and fixed at 6pm
I've been asked about it several times lately, so I'll just put here an oldie that I've been using for a few years now untouched:
1: // MIT license
2: // Copyright 2005-2008 Ken Egozi
3: //
4: // Permission is hereby granted, free of charge, to any person obtaining a copy
5: // of this software and associated documentation files (the "Software"), to deal
6: // in the Software without restriction, including without limitation the rights
7: // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8: // copies of the Software, and to permit persons to whom the Software is
9: // furnished to do so, subject to the following conditions:
10: //
11: // The above copyright notice and this permission notice shall be included in
12: // all copies or substantial portions of the Software.
13: //
14: // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15: // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16: // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17: // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18: // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19: // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20: // THE SOFTWARE.
21:
22: using System;
23: using System.Collections.Generic;
24: using System.Text;
25: using System.Security.Cryptography;
26: using System.Collections;
27:
28: namespace KenEgozi.CryptographicServices
29: {
30: public static class Hashing
31: {
32: private static Hashtable hashAlgorithms = Hashtable.Synchronized(new Hashtable());
33:
34: /// <summary>
35: /// Hashing a given string with SHA2.
36: /// </summary>
37: /// <param name="data">Data to hash</param>
38: /// <returns>Hashed data</returns>
39: public static string HashData(string data)
40: {
41: return HashData(data, HashType.SHA256);
42: }
43:
44: /// <summary>
45: /// Hashing a given string with any of the supported hash algorithms.
46: /// </summary>
47: /// <param name="data">Data to hash</param>
48: /// <param name="hashType">Hashing algorithm to use</param>
49: /// <returns>Hashed data</returns>
50: public static string HashData(string data, HashType hashType)
51: {
52: HashAlgorithm hash = GetHash(hashType);
53: byte[] bytes = (new UnicodeEncoding()).GetBytes(data);
54: byte[] hashed = hash.ComputeHash(bytes);
55: StringBuilder sb = new StringBuilder(64);
56: foreach (byte b in hashed)
57: sb.AppendFormat("{0:x2}", b);
58: return sb.ToString();
59: }
60:
61: private static HashAlgorithm GetHash(HashType hashType)
62: {
63: if (!hashAlgorithms.ContainsKey(hashType))
64: hashAlgorithms.Add(hashType, CreateaHashAlgorithm(hashType));
65: return hashAlgorithms[hashType] as HashAlgorithm;
66: }
67:
68: private static HashAlgorithm CreateaHashAlgorithm(HashType hashType)
69: {
70: switch (hashType)
71: {
72: case HashType.MD5:
73: return new MD5CryptoServiceProvider();
74: case HashType.SHA1:
75: return new SHA1Managed();
76: case HashType.SHA256:
77: return new SHA256Managed();
78: case HashType.SHA384:
79: return new SHA384Managed();
80: case HashType.SHA512:
81: return new SHA512Managed();
82: default:
83: throw new NotImplementedException();
84: }
85: }
86: }
87:
88: public enum HashType
89: {
90: MD5,
91: SHA1,
92: SHA256,
93: SHA384,
94: SHA512
95: }
96: }
Not beautiful, however useful.
You can download this file from here (just remove the .txt - the server doesn't serve .cs files directly)
btw, the colouring of the source was made with the help of http://www.manoli.net/csharpformat/, even though I had to do some manual tweaking to make it work with this blog. If colours of reserved words, comments etc. do not appear, then please refresh your browser's cache to get the updated css
An innocent question raised by Ayende has started an interesting debate on the comments.
In short (read it all there - don't be lazy)
Which interface name is better?
a. IRecognizeFilesThatNeedToBeIgnored
b. IIgnoreFilesSpecification
with a single method: ShouldBeIgnored(string file);
Some were in favour of a, some in favour of b.
The interesting thing is that many has offered a third option:
c. IFileFilter
Let's group these things:
Personally I couldn't care less which one of the first type will be used. I slightly in favour of b., as I think funny names are good. The compiler cares nothing about names, but the human mind would remember the purpose well, and a newcomer would pick it up quickly.
The second group (IFileFilter) is not good. It might get filled with a lot of methods that do file filtering.
and if it's not, I think it should reflect the intention of the implementing class.
Since multiple interfaces per class are allowed, it's ok to have specialised ones.
MonoRail runs on .NET 2.0. AspView is no different, and is compiled for .NET 2.0, so people who cannot run 3.5 (shared hosting, other limitations) can still enjoy every shining new feature.
However, if you DO want to use c#3 stuff in view templates (like extension methods), then you can. Thanks to Felix Gartsman, the AspView compiler would try to load the c# compiler based on the codedom section of the application .config file.
So, if you're using autorecompilation=true, the add this to your web.config:
<system.codedom>
<compilers>
<compiler language="c#;cs;csharp"
extension=".cs"
type="Microsoft.CSharp.CSharpCodeProvider,System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
warningLevel="4">
<provideroption value="v3.5" name="CompilerVersion" />
<provideroption value="false" name="WarnAsError" />
</compiler>
</compilers> </system.codedom>
If you want to precompile your views, then add the same to vcompile's app.config.
From the website:
Current version includes following features:
The coolest thing is the ability to spell check identifiers. I'd love it.
It's at http://www.agentsmithplugin.com/ and I found out about it on Castle's dev list (thx Victor)
There appear to be yet another XML API.
So, when you want to generate:
<?xml version="1.0" encoding="utf-8"?>
<root>
<result type="boolean">true</result>
</root>
instead of (using System.XML):
XmlDocument xd = new XmlDocument();
xd.AppendChild(xd.CreateXmlDeclaration("1.0", "utf-8", ""));
XmlNode root = xd.CreateElement("root");
xd.AppendChild(root);
XmlNode result = xd.CreateElement("result");
result.InnerText = "true";
XmlAttribute type = xd.CreateAttribute("type");
type.Value = "boolean";
result.Attributes.Append(type);
root.AppendChild(result);
one can (using the new API):
XmlOutput xo = new XmlOutput()
.XmlDeclaration()
.Node("root").Within()
.Node("result").Attribute("type", "boolean").InnerText("true");
Exciting.
Or is it?
Why not just (using your template-engine of choice):
<?xml version="1.0" encoding="utf-8"?>
<root>
<result type="<%=view.Type%>"><%=view.Value%></result>
</root>
works great for the "complex" scenarios on Mark S. Rasmussen's blog:
<?xml version="1.0" encoding="utf-8"?> <root> <numbers>
<% foreach (Number number in view.Numbers) { %> <number value="<%=number%>">This is the number: <%=number%></number>
<% } %> </numbers> </root>
and:
<?xml version="1.0" encoding="utf-8"?> <root> <user> <username><%=view.User.Username%></username> <realname><%=view.User.RealName%></realname> <description><%#view.User.Username%></description>
<articles>
<% foreach (Article article in view.User.Articles) { %> <article id="<%=article.Id%>"><%#article.Title%></article>
<% } %> </articles> <hobbies> <% foreach (Hobby hobby in view.User.Hobbies) { %>
<hobby><%#hobby.Name%></hobby>
<% } %>
</hobbies> </user> </root>
is Hobby and Article more complex? no probs. break it down to sub-views:
<?xml version="1.0" encoding="utf-8"?> <root> <user> <username><%=view.User.Username%></username> <realname><%=view.User.RealName%></realname> <description><%#view.User.Username%></description>
<articles>
<% foreach (Article article in view.User.Articles) { %>
<subview:Article article="<%=article%>"></subview:Article>
<% } %> </articles> <hobbies> <% foreach (Hobby hobby in view.User.Hobbies) { %>
<subview:Hobby hobby="<%=hobby%>"></subview:Hobby>
<% } %>
</hobbies> </user> </root>
Can you get more expressive that that?
Look how easy it is to visualize what we're rendering, and how easy it is to change.
I consider all those XML API (including ATOM/RSS writers) as a leaky and unneeded abstractions, just like WebForms. Do you?
Yep, I've made yet another noob mistake.
I needed to compare two enum values, on a method that was accepting objects.
public string Whatever(object currentOption, object selectedOption)
{
return
currentOption == selectedOption
? "class='active' "
: string.Empty;
}
Didn't work.
However,
public string Whatever(object currentOption, object selectedOption)
{
return
currentOption.Equals(selectedOption)
? "class='active' "
: string.Empty;
}
Did work.
so, it appear that == isn't polymorphic so it did the object.Equals method which apparently looks for reference equality, rather than the enum Equals.
And that has been yet another future-reference-post ...
Have just read Ayende's post about C#/Java vs Boo/Ruby.
Tried to comment, but then I decided it's worth a post.
I'd say that the difference is MAF - Management Acceptance Factor
Boo is also a way too cool/strange/creepy name for a distinguished suit to grasp.
It's like when you're a collage girl, and you want to introduce your new boyfriend to your mama. It doesn't matter that he has a BSc and MBA plus 3 castles in the Swiss alps. If he'd first show up to the family on his way-too-cool motorcycle, then you're going to be grounded.
When I approached my last manager about MonoRail, and told him that the views will be written in 'Boo', he got all scared. Then I wrote AspView, views to be written in c#, and he gave consent to go MonoRail.
Even though, at least at that time, Brail was way more mature than AspView.
The 'cooler' languages needs to be marketed to management.
Ruby works in Eclipse. I wonder who is going to start an OSS effort to create a decent Boo plugin for VS2008 (based on the VS2008 shell).
Make it demoable, make it look 'official', and MAF would go way higher.
I've spent some times lately with Linq To SQL and have played a bit with the Mapping namespace.
Why I do not like it very much is a matter for a different post. The matter at hand is that I want the power of Linq, and I want the power of NHibernate, and I want the easy road of ActiveRecord.
What do I mean by that? I'd like:
the needed prequisites:
So, Ayende has kick-started it, and with some help from Bobby Diaz, we have a prototype level NHibernate provider for Linq.
To make it work with ActiveRecord, all you need is to add:
using System;
using Castle.ActiveRecord;
using Castle.ActiveRecord.Framework;
using NHibernate;
namespace NHibernate.Linq
{
public class ActiveRecordContext : NHibernateContext
{
public ActiveRecordContext() : base(null)
{
session = GetSession();
}
private ISession GetSession()
{
ISessionScope scope = SessionScope.Current;
if (scope == null)
throw new InvalidOperationException("You should be in a SessionScope()");
ISessionFactoryHolder holder = ActiveRecordMediator.GetSessionFactoryHolder();
return holder.CreateSession(typeof(ActiveRecordBase));
}
}
}
and now you can do stuff like:
using (new SessionScope())
{
ActiveRecordContext context = new ActiveRecordContext();
var q =
from c in context.Session.Linq<Category>()
select c;
foreach (Category c in q)
Console.WriteLine(c.Name);
}
Assuming Category has [ActiveRecord] mapping.
Following my last post on the DictionaryAdapter, I'll demonstrate here how you can get typed access to your views' properties.
What it requires from you:
1. Declare an interface for each of your views. That is a Good Thing anyway, as designing to a contract is a good best practice, and it allows for easy testing.
2. Have a base class for your controller that would define TypedFlash and TypedPropertyBag. Not mandatory, but very convenient.
3. Use the newest build of AspView. Again - not mandatory, but helpful.
Now for the showtime.
First we would create a base class for our controllers, with a TypedPropertyBag and TypedFlash properties:
public abstract class Controller<IView> : SmartDispatcherControllerController
where IView : class
{
IDictionaryAdapterFactory dictionaryAdapterFactory;
IView typedPropertyBag;
IView typedFlash;
protected IView TypedPropertyBag
{
get
{
if (typedPropertyBag == null)
typedPropertyBag = dictionaryAdapterFactory.GetAdapter<IView>(PropertyBag);
return typedPropertyBag;
}
}
protected IView TypedFlash
{
get
{
if (typedFlash == null)
typedFlash = dictionaryAdapterFactory.GetAdapter<IView>(Flash);
return typedFlash;
}
}
protected override void Initialize()
{
base.Initialize();
IDictionaryAdapterFactory dictionaryAdapterFactory = new DictionaryAdapterFactory();
}
}
tip:
You can look at a more complete version of that base-class, written by Lee Henson (who have made some improvements to the original DictionaryAdapter, and also have introduced me to Peroni Beer).
The base controller also declares a type parameter for a Session DictionaryAdapter, hooks into the Castle.Tools.CodeGenerator, and uses IoC for DI.
Talking about those issues is a separate subject, for other posts.
Now let's create the view contract. A rather stupid example would be:
public interface IStupidView
{
Guid Id { get; set; }
string Name { get; set; }
}
controller:
public class StupidController : Controller<IStupidView>
{
public void Index()
{
}
public void DoStuff(string name, string password)
{
if (password != "AspView Rocks")
{
TypedFlash.Name = name;
TypedFlash.Message = "Wrong Password";
RedirectToAction("Index");
return;
}
TypedPropertyBag.Id = Guid.NewGuid();
TypedPropertyBag.Name = name;
}
}
view (Index.aspx):
<%@ Page Language="C#" Inherits="Castle.MonoRail.Views.AspView.ViewAtDesignTime<IStupidView>" %>
<%
%>
<p><%=view.Message %></p>
<form action="DoStuff.rails">
Name: <input type="text" name="name" value="<%= view.Name %>" /> <br />
password: <input type="password" name="password" /> <br />
<input type="submit" />
</form>
view (DoStuff.aspx):
<%@ Page Language="C#" Inherits="Castle.MonoRail.Views.AspView.ViewAtDesignTime<IStupidView>" %>
<%
%>
The data was: <br />
Id: <%= view.Id %>, Name: <%= view.Name %>
Look at the intellisense (and at my ultra-cool black color scheme):
Things to notice:
1. Do not forget to reference the Assembly that has the view interface declaration. On the test site within aspview's source repository the interface is declared in the Web project (AspViewTestSite), so the web.config has this:
view (Index.aspx):
<aspview ... >
...
<reference assembly="AspViewTestSite.dll"/>
...
</aspview>
2. you can use the DictionaryAdapter directly, on older versions of AspView (and on WebForms aspx/ascx files) by simply grabbing an adapter manually. sample:
...
<% IMyViewContract view = new Castle.Components.DictionaryAdapter.DictionaryAdapterFactory()
.GetAdapter<IMyViewContract>(Properties); %>
...
blah blah <%=view.UsefulProperty %>
...
Ok, cut the crap. where can I get it?
UPDATE:
The DictionaryAdapter was initially written by the guys from Eleutian as part of Castle.Tools.CodeGenerator.
Another nice news from Scott Guthrie:
a small excerpt:
Today I'm excited to announce that we'll be providing this with the .NET 3.5 and VS 2008 release later this year.
I hate switch statements. They just looks bad.
So take a look at a nice example I've read at Luca Bolognese's, for switching from a switch based code to a cleaner one.
The syntax in pre-c#3 would be less nice (delegate() instead of lambda, and parseFuncs.Add instead of the initializer) but it's doable.
Heck, it reminds me of some old university-level Ansi-C code I've once wrote for a matrix-calculator program:
typedef struct {
char * name;
char * (*func)(char *);
char * description;
} cmd_class;
// matrix functions.
// pre: parameter string. post: answer is printed or stored in matrix
char * read_mat(char * parm_string);
char * print_mat(char * parm_string);
char * add_mat(char * parm_string);
char * sub_mat(char * parm_string);
char * mul_mat(char * parm_string);
char * mul_scalar(char * parm_string);
char * trans_mat(char * parm_string);
cmd_class cmd[] = {
{"read_mat", read_mat, "parameters: matrix,val1[,val2,...,val16]"},
{"print_mat", print_mat, "parameters: matrix"},
{"add_mat", add_mat, "parameters: matrix_A,matrix_B[,target_matrix]"},
{"sub_mat", sub_mat, "parameters: matrix_A,matrix_B[,target_matrix]"},
{"mul_mat", mul_mat, "parameters: matrix_A,matrix_B[,target_matrix]"},
{"mul_scalar", mul_scalar, "parameters: matrix,scalar[,target_matrix]"},
{"trans_mat", trans_mat, "parameters: matrix[,target_matrix]"},
{"stop", stop, "exit program"},
{"menu", print_menu, "print this menu"},
{"not_valid", NULL, "NULL"}
};
It allowed me to avoid switch by looping over the cmd[] array in a helper method, thus able to do
command(commandName).func(params);
Not exactly a typical jet-fighter-realtime-c-code, but it gave me a better looking code, and a 100/100 grade.
Today I was informed by Dror that although I managed to redirect all requests to html/aspx url's on my blog (the ones that dagBlog was using) to the new pemalink format, I forgot to do the same for the old syndication link.
So that link was http://www.kenegozi.com/blog/SyndicationService.asmx/GetRss and now it's http://www.kenegozi.com/Blog/Syndication/Atom.aspx
I could've used the monorai redirection module that is already in use on my blog, but I chose to do it differently, with a dedicated handler, just to show how easy it is do to such stuff, even without a full blown redirection engine.
So, I've added this:
public class SyndicationRedirectionHandler : IHttpHandler { #region IHttpHandler Members public bool IsReusable { get { return true;} } public void ProcessRequest(HttpContext context) { context.Response.StatusCode = 301; context.Response.Redirect("http://www.kenegozi.com/Blog/Syndication/Atom.aspx"); } #endregion }
and that line into web.config:
<add verb="*" path="SyndicationService.asmx" type="KenEgozi.Com.Weblog.SyndicationRedirectionHandler, KenEgozi.Com.Weblog"/>
Voila.
What we have:
1. Default Helpers are now declared in the AspViewBase. It means that you can use <%=FormHelper.LabelFor(...) %> without the need to declare the helper at the begining of the view.
2. the compiler was refactored to allow for better testing, and for implementation of further view languages. vurrently I've started with VB.NET but it is not working yet, since I have no time to make sure the VB syntax is correct. The tests of the compiler are missing due to some stupidity on my side, of not commiting the TestCase ...
I've wanted to let svn access but I have some trouble with that. I've started a sourceforge project but I cannot upload the repo to the site. I did all they've asked on the site but the import process reporting failure no matter what I do. I guess that the best way will be if the Castle team would allow AspView into it's codebase, maybe on the Contrib repo to begin with ...
So meanwhile you can download the current bits from here.
Keep me posted,
Ken.
So I'm releasing AspView.
You can download the source from here.
It was written against the Castle 1.1 from the trunk, build no. 152.
Please note that in order to run the TestCases you'd have to make sure that the latest Castle.MonoRail.TestSupport is in the GAC.
The documentation is poor since I have a little time now. I am working on a website for my employer (that utilizes AspView and AR) and until the first beta release I won't have time to do anything but major bugfixes. This project isn't open sourced so I won't be able to share it's sources, however since this will be a public site, it would serve as a Proof Of Concept to the MonoRail and AspView.
The views MUST have the following structure:
a. Page header - Must be present for intellisense to work:
1: <%@ Page Language="C#" Inherits="Castle.MonoRail.Views.AspView.ViewAtDesignTime" %>
b. Directives - Not mandatory:
1: <%@ Import Namespace="System.Text" %>
2: <%@ Import Namespace="System.Drawing" %>
c. Properties decleration - Currently it's mandatory. If you have no properties you mast have an empty block:
1: <%
2: string[] strings;
3: DateTime today;
4: int index;
5: %>
or just
1: <%
2: %>
d. View body
In a layout view you place the inner view using the ViewContents property, like this:
1: blah
2: blah
3: <%=ViewContents%>
4: blah
5: blah
So what is AspView?
It is a Visual Studio 2005 friendly ViewEngine implementation.
The scripting is done using VisualStudio languages (c# and VB.NET). The views are precompiled, (or can be compiled on-demand, but anyway not interpreted).
The project was inspired by the Brail ViewEngine, but since it doesn't use Boo it is more Management-Friendly, since they need not worry about getting out of the "safe" microsoft world.
I tend to like Boo as a language very much, and I like Brail a lot, too (since it allows for less code in the view thanks to the Boo magic) but I lack the tight Visual Studio integration (opening .boo files in #Develop messes up my desktop), and the intellisense is quite important, at least for the developers I worl with.
So I will post in the next few days about it, and I'll make it available to be downloaded (source and binary) as soon as I'll test it a little more. I hope to have a public svn repository soon.
A little demo view:
1: <%@ Page Language="C#" Inherits="Castle.MonoRail.Views.AspView.ViewAtDesignTime" %>
2: <%
3: string[] strings;
4: %>
5:
6:
7: hello from index<br />
8: This are the strings:<br />
9: <% foreach (string s in strings) { %>
10: <%=s %><br />
11: <% } %>
12:
13: <br />
14: End of normal view
15: <br />
16: <% OutputSubView("Home/SubViewSample"); %>
There is a great article on CodeProject, by Guenter Prossliner.
A simple class in presented there, that makes Duck Typing possible for Generics enabled CLS languages (VB.NET 8 and C#2.0 for instance).
I'll present it here in short form:
let's say we have two classes:
1: class Foo1
2: {
3: public string Bar() { }
4: }
5: class Foo2
6: {
7: public string Bar() { }
8: }
Now you have a method that can work with instances of eiether one, and invoke Bar on it:
1: void SimpleMethodOnFoo1(Foo1 foo)
2: {
3: foo.Bar();
4: }
5: void SimpleMethodOnFoo2(Foo2 foo)
6: {
7: foo.Bar();
8: }
I am working with AR for a few month now, ignorantly ignoring the Castle Project's wiki.
Stupid I am. I could have learned a lot and save a bunch of wandering around the net and the intellisense to learn obvious stuff.
Thanks to hammett who pointed me there.
Anyway - now I read it from <html> to </html>, and I saw the part about running HQL using the Execute Callback
There are examples, each one with two flavors: "not using generics", and "using generics". Well, the one about the Execute Callback is misleading. It should have been "not using anonymous method" and "using anonymous methods", since the second one does not use generics.
So I thought - let's make the API simpler.
We would have like to allow the user execute her hql like that:
1: public static Post[] GetPostsByAuthorName(string authorName)
2: {3: return (Post[])Execute(typeof(Post), "from Post p where p.Author = ?", authorName);
4: }Or even better, by using generics (this time for real):
1: public static Post[] GetPostsByAuthorName(string authorName)
2: {3: return Execute<Post>("from Post p where p.Author = ?", authorName);
4: }Here is the magic:
1: public static T[] Execute<T>(string hql, params object[] parameters)
2: {3: IList untypedResults = (IList)Execute(delegate(ISession session, object data)
4: {5: object[] queryParams = (object[])data;
6: IQuery query = session.CreateQuery(hql);7: for (int position = 0; position < queryParams.Length; ++position)
8: query.SetParameter(position, queryParams[position]);9: return query.List();
10: }, parameters);11: T[] results = new T[untypedResults.Count];
12: untypedResults.CopyTo(results, 0);13: return results;
14: }I'll add an overload that will accept named parameters. I am not sure about the right way to do that, though.
My options are:
1: Execute<T>(string hql,
2: string[] paramNames,
3: Type[] paramTypes, 4: object[] parameters)
Or:
1: Execute<T>(string hql, IParameter[] parameters)
where IParameter definition is something like:
1: public interface IParameter<T>
2: where T: Type
3: {4: public string Name { get; set;}
5: public T Value { get; set;}
6: }Maybe both?
And maybe I haven't read the wiki thoroughly enough and there are already implementations for all that?
The reference I've used while learning to use Castl'e ActiveRecord implementation is the Blog/Post demos that can be found on Castle's site.
Let's look at the Type Hierarchy example, that can be found here.
It shows an implementation of a class diagram that look a little bit like this:
Let's look at the code :
But look what happens. since the Id property on entity is public and inherited to the subclasses, you get something like this:
So there is a duplicate field here !!!. and it's not only a getter-setter thingie. It also have different private members.
My solution for this is to virtualize the base Id, and protectedize (hehe) the _id member, like this:
[ActiveRecord("entity"), JoinedBase]
public class Entity : ActiveRecordBase
{
protected int _id;
[PrimaryKey]
public virtual int Id
{
get { return id; }
set { id = value; }
}
}
[ActiveRecord("entitycompany")]
public class CompanyEntity : Entity
{
[JoinedKey("comp_id")]
public override int Id
{
get { return _id; }
set { _id = value; }
}
}
[ActiveRecord("entityperson")]
public class PersonEntity : Entity
{
[JoinedKey("person_id")]
public override int Id
{
get { return _id; }
set { _id = value; }
}
}
And before you hit me with a big stick - I do know of ActiveRecordBase<T> . :) the above code is for demonstration purposes only, not to be Copy&Pasted to your Brand-New-Best-Erp-Ever-Made-And-Will-Make-You-Rich
Check this out.
I've wanted to send emails, and have messages with both plain text and html views. A quick look at MSDN have braught this up, and it looked good. Waydago MSFT - good work.
However, a strange exception occured in runtime, and after a little check it was obvious that the constructor used in MSDN's doc is just NOT THERE.
This guy also had the same problem, and someone there pointer out the solution. There is a static method to create an instance of a AlternateView from a string that represents a message's body. It's called CreateAlternateViewFromString and It's nice to have it.
Mistakes in docs are exceptable, however, the guy braught it up last January, and MSFT didn't fix the doc until now.
Strange it is.
I'm going to explore a few ways to spawn new threads in c# 2.0.
Let's say that we want to do a time consuming process, and that we do not need that the main program will wait for it to end.
For the sake of the examples here, I'll assume that the long run process is sending an e-mail to "you", from "me" and the message's body is "the body of the message". the email will be processed by a thread-safe(1) static method, called SendMail(string, string, string) that resides in the Utilities class. How convenient.
(1) A thread-safe method is an enchanted, voodoo-enabled method that behaves well under multithreading (2) environment.
(2) Multithreading is a cool name for the ability to knit long sleeved shirts(3)
(3) Disregard the last three comments. Really, you should.
The non-multithreading code looked like this:
Ugly.
Luckily, .NET 2.0 comes with anonymous delegates, that simplifies things a lot:
In the next few days I'll introduce a helper class (well, I think it helps) that encapsulate the things you need to do to spawn a new thread, pass parameters to it, and be notified on it's lifecycle.
sources, etc. will be here soon, too
I'm developing some Two-Way Databound ASP.NET Server Controls lately, and I use some reflection in order to do the actual binding and unbinding.
During my work, I found out something strange.
Let's consider the next code segment:
bool? myNullableBool = true;
Type t = myNullableBool.GetType();
You'd think that t == typeof(bool?),
but actually, t == typeof(bool)!!!
So it seams that the Nullable<> types in c# 2.0 aren't "real", in the sense that instances of those types, actually are of the corresponded "regular" type, but has some kind of an overload on the = operator, that allow null as a input value.
It's not the behavior that I've expected, and so it caused my a lot of headaches during the development of my binding/unbinding methods.
I guess it is documented on MSDN, but I got to excited about the nullable types feature, that I've started using it without fully understanding it.
So my lesson for today is: study well, and stay out of hell.