ASP.NET
As you probably know by now (i.e. from Phill's blog), however both Routing and Abstractions are. MVC Preview 4, however, has its own version of both assemblies.
In order to get MVC to use the new RTM bits of both assemblies (and avoid weird side-by-side errors), you just need to add the following binding redirect to the web.config file:
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Web.Abstractions" publicKeyToken="31bf3856ad364e35"/>
<bindingRedirect oldVersion="0.0.0.0" newVersion="3.5.0.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.Routing" publicKeyToken="31bf3856ad364e35"/>
<bindingRedirect oldVersion="0.0.0.0" newVersion="3.5.0.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.Extensions" publicKeyToken="31bf3856ad364e35"/>
<bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="3.5.0.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.Extensions.Design" publicKeyToken="31bf3856ad364e35"/>
<bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="3.5.0.0"/>
</dependentAssembly>
</assemblyBinding>
</runtime>
The other two redirects are added automatically by a Dynamic Data website, so I figured out it's better to put them there too :)
The latest MVC release adds some pretty cool usage of LINQ expression trees. It's another example of how cool (and WAY beyond querying) LINQ is.
Specifically, you can now replace untyped, "magic" strings when rendering links like:
<%= Html.ActionLink("Sign up", "SignUp", "UserController", true) %>
to type-safe and therefore compile-time checked code:
<%= Html.ActionLink((UserController c) => c.SignUp(true), "Sign up") %>
or the equivalent syntax:
<%= Html.ActionLink<UserController>(c => c.SignUp(true), "Sign up") %>
Basically MVC takes an Expression Tree with the invocation (which is actually a "potential" invocation) and makes up an HTML anchor with the url that corresponds to the controller, action and parameters. The relevant code from the MVC sources is in Mvc\Extensions\LinkExtensions.cs:
public static string ActionLink<T>(this HtmlHelper helper, Expression<Action<T>> action, string linkText, object htmlAttributes) where T : Controller {
//TODO: refactor this to work with ActionLink in the core
string linkFormat = "<a href=\"{0}\" {1}>{2}</a>";
string atts = string.Empty;
if (htmlAttributes != null)
atts = HtmlExtensionUtility.ConvertObjectToAttributeList(htmlAttributes);
string link = BuildUrlFromExpression(helper, action);
string result = string.Format(CultureInfo.InvariantCulture, linkFormat, link, atts, helper.Encode(linkText));
return result;
}
and LinkBuilder.cs:
public static string BuildUrlFromExpression<T>(ViewContext context, Expression<Action<T>> action) where T : Controller {
MethodCallExpression call = action.Body as MethodCallExpression;
if (call == null) {
throw new InvalidOperationException("Expression must be a method call");
}
if (call.Object != action.Parameters[0]) {
throw new InvalidOperationException("Method call must target lambda argument");
}
string actionName = call.Method.Name;
// TODO: Use better logic to chop off the controller suffix
string controllerName = typeof(T).Name;
if (controllerName.EndsWith("Controller", StringComparison.OrdinalIgnoreCase)) {
controllerName = controllerName.Remove(controllerName.Length - 10, 10);
}
RouteValueDictionary values = BuildParameterValuesFromExpression(call);
values = values ?? new RouteValueDictionary();
values.Add("controller", controllerName);
values.Add("action", actionName);
VirtualPathData vpd = RouteTable.Routes.GetVirtualPath(context, values);
return (vpd == null) ? null : vpd.VirtualPath;
}
Together with other examples like the type-safe/strong-typed reflection sample and Moq, I hope you're starting to see the possibilities enabled by turning code into data.
Extending RedirectToAction
I think we'll see the same pattern throughout the MVC framework, but at this time, you still have to use magic strings in some places:
this.RedirectToAction("AddNew", "RegistrationController");
It's quite common the need to redirect from one controller action to a different controller action, passing some data around. In order to avoid having magic strings with controller names and action names throughout the place, we had this pattern in a few places (with the previous ASP.NET MVC release):
public class RegistrationController : Controller
{
public static object AddNewRedirectData(string id)
{
return new { controller = "Registration", action = "AddNew", id = id };
}
public void AddNew(string id)
{
}
}
Then another controller that wanted to redirect to the AddNew action, instead of referring to the controller and action by name, would do:
RedirectToAction(RegistrationController.AddNewRedirectData(id));
This was less than ideal, but it worked. But we needed to add a "xxxRedirectData" method for each action that wanted to encapsulate the magic strings. So I set to fix this by using the same approach shown above with expression trees, and came up with the following:
this.RedirectToAction((RegistrationController c) => c.AddNew(id));
And it's looking much better now :). The code is very similar to the one shown above:
public static void RedirectToAction<T>(this Controller controller, Expression<Action<T>> action)
{
MethodCallExpression call = action.Body as MethodCallExpression;
if (call == null)
{
throw new InvalidOperationException("Expression must be a method call");
}
if (call.Object != action.Parameters[0])
{
throw new InvalidOperationException("Method call must target lambda argument");
}
string actionName = call.Method.Name;
// TODO: Use better logic to chop off the controller suffix
string controllerName = typeof(T).Name;
if (controllerName.EndsWith("Controller", StringComparison.OrdinalIgnoreCase))
{
controllerName = controllerName.Remove(controllerName.Length - 10, 10);
}
var values = LinkBuilder.BuildParameterValuesFromExpression(call);
values.Add("action", actionName);
values.Add("controller", controllerName);
VirtualPathData vpd = RouteTable.Routes.GetVirtualPath(controller.ControllerContext, values);
string target = null;
if (vpd != null)
{
target = vpd.VirtualPath;
}
controller.HttpContext.Response.Redirect(target);
}
Quite some time ago I started warning people about an important feature that was removed from ASP.NET Whidbey: non-visual components (IComponent-based classes). I logged the bug in Product Feedback, which resulted in a major number of votes that eventually draw some attention internally and resulted in the last update status which is Fixed.
Now that Whidbey Beta2 has finally hit the streets, it's time to regress the bug and see if it's really fixed. What follows is what I found (hint: another deception point).
I focus the discussion of the features that are missing on the article I published on CodeProject that showcases the full power of non-visual components and the extender provider model in v1.x.
First of all, instead of restoring the "Components Tray", they force you to right-click on the .aspx file and select View Component Designer:
That wouldn't be terribly bad, except for the consequences:
- Extender Providers no longer work: the component is no longer officially part of the web form, but something that lives "behind" and that you have to see through a different designer. This means that the forms designer has no knowledge whatesoever about extender providers as it used to have. The following extension of built-in controls is no longer possible:

- Designers/editors no longer work: if a designer relied on showing information from the current page, that won't work either. That's basically because the new designer surface you get is not the one for the form at all, but a new one created for non-visual components. That means that all controls on the form, which used to live in the same container (
IContainer, specifically) as your own components, no longer do. Effectively, you have no way of retrieving the controls that exist on the design surface of the forms editor. This is even if the IDesignerHost service (that you can still ask for) Container property contains a Page object, and that's because it's empty of controls :S:S. The following kind of editor is no longer possible:


- Components don't show up in the Toolbox: there's no way to make components appear in the toolbox. Even if they do show up in the Customize Toolbox dialog, and you can select them, they will never show up in the toolbox. As a consequence, there's no way to drop new components on a form. How are you supposed to use them therefore? The only way is through the components designer surface, with the problems mentioned above.
Therefore, one of the most important uses of a component, which was to extend and interact with the form's UI elements, in nicely decoupled way (you didn't need to inherit any of the built-in controls to add functionality to them), is no longer possible.
Interestingly, WinForms developers continue to enjoy this feature, and the code generation part was made more robust and clean with the introduction of partial classes. I see this as a sign of commiting with an existing feature and working to improve it where it was lacking, as opposed to starting from scratch again and leaving the customers guessing what the hell happened to their investment.
Maybe I'm just too pesimist. But this doesn't look like a fix at all for my bug, and it certainly cuts so many of the features of non-visual components that it renders them pretty much useless. Hence, it only makes sense for me to reactivate the bug and ask once more for your cooperation in voting for this feature to come back once more. Go and vote the bug if you feel this is an important feature being lost.
Regular expressions are really powerful and very cool. Most people think of them as just a validation mechanism. They are missing a big scenario enabled by regexes: parsing.
Some other people think that if you're doing any parsing, you **have** to use parser generator tools (i.e. yacc/lex, antlr, coco/r, etc), build a formal grammar of your language, etc. But do you really **need** to get into that? Do you want proof that you can achieve the same goal with regular expressions? The ASP.NET page parser is built with regular expressions, and not only the v1.x, but the Whidbey version too.
Wanna confirm? Fire up Reflector, search for the TemplateParser class in the System.Web.UI namespace, and look at the ParseStringInternal method. There you will see how the BaseParser class is being used to parse the page source, which contains all the regular expressions for the several pieces of a page.
I've build a number of parsers with regexes, from simple expression parsers (i.e. a more flexible and powerful expression format than DataBinder.Eval, for example) to full template file parsing (i.e. templates with ASP-like syntax for codegen, in the spirit of CodeSmith, NVelocity, etc.). And it works very well. And your code using very complex regular expressions doesn't have to be a cryptic-impossible to read-never ending-line of almost garbage that only you can understand.
Bottom-line: learn regular expression. There're a lot of very real problems that you can solve SO easily with them...
For
quite some time now, I've been trying to raise developer's (and MS) awareness of how an unbelievable bad idea it is to
remove an amazing feature in ASP.NET v1.x and replace it with a bad, already tried and failed one in v2. Even given the overwhelming feedback (
151 voters with an average of 4.7 over 5),
Microsoft decided not to fix it, but they gave the wrong reasons for it.
The main reason was that "the existing model in VS 2003 was prone to bugs and code-loss and as such we've removed the functionality of a designer tray for components defined in InitializeComponent.". I reopened the bug and added:
"The Windows Forms designer keeps supporting the Component Tray just as it used to, so I think they somehow solved the "prone to bugs and code-loss" nature in it, right?
I can't see how given that it's working on WinForms, you can't take advantage of it. It's a very important feature to be able to develop components that are reusable across view technologies. This is the last time I'll reopen the bug. I just want an answer and if you're planing to put it back as it was (that is, 100% compatible with the WinForms support and codegen features) or if you're going to break the model anyway."
I'll keep bothering these guys until they give us component developers a satisfactory answer. If you agree, you should definitely
make your voice loud and clear.
A couple months ago I posted about a major regression happening in ASP.NET v2. It's amazing that even after an overwhelming difference of 10 to 1 people voting to keep the Components tray in the designer, which allowed wizards, designer verbs, and extender providers to provide an incredible powerful enhanced visual experience in the IDE, Microsoft decided not to fix it.
So, you can kiss bye-bye to your UI-technology agnostic components and IDE integration. You'll have to keep two codebases and use the ugly gray-rendered "controls" (can't understand why you have to inherit from Control or WebControl if you're not doing any UI stuff, and why it has to live in the HTML design surface). A huge step backwards in what seemed to me like an important evolutionary step towards software factories based on highly reusable components.
They definitely ruined my day. But I plan to publish an extensive article of what you'll lose, and all the features you can exploit from this powerful model. Hopefully, if I get enough developers to use it, they will put more effort in bringing it back.
Before I get to the point where I expect to convince you of what we're loosing with ASP.NET v2, I'll make a brief recap, just in case you haven't used the technique in question.
What are components?
Components, in the strict .NET sence, is anything that directly or indirectly implements IComponent. You'd be surprised that a lot of classes in .NET (specially visual ones, such as System.Web.UI.Control or System.Windows.Forms.Control) implement IComponent. One of the consequences of a class being a component is that the IDE can offer additional features to it at design time. The key property for the IDE to offer services to components is the IComponent.Site. A so-called sited component is one that has been placed in a Container. This containment is general and is not related to visual containment.
For example, an ASP.NET server control, when dropped in a Web Form, is said to be sited. Its Site property (part of the implementation of the IComponent interface), is set to the host where the component lives now, which inside VS .NET is an instance of the Microsoft.VisualStudio.Designer.Host.DesignSite class. Exactly the same object type is assigned as the Site property of a Windows Forms user control when dropped in the forms designer, and to a non-visual component at design-time.
The Site property, of type ISite, contains members that allow the component to communicate with other components, with its container (a logical container) and services provided by it. The container is an object that implements the System.ComponentModel.IContainer interface. At design-time, the container is always an instance of the Microsoft.VisualStudio.Designer.Host.DesignerHost. This object is the core of VS .NET IDE features for components.
Now, in ASP.NET 1.x, you have a clear distinction between visual components such as controls and non-visual ones, which appear in a separate area called the "component tray". In the highly unlikely event that you never saw it before, here's how it looks like:

Why are they cool?
One up-front benefit of non-visual components and the way ASP.NET *and* Windows Forms handle them (up to now, both handle them in the same uniform way), is that they don't clutter the visual design of the form with items that are not supposed to be rendered.
Other important benefits are:
- Component designers: you can assign a designer to a component, which will enhance the component behavior at design time. Many of the following points are related to designers.
- Designer verbs, wizards: a component designer can expose so called designer verbs so that the user can trigger pottentially complex actions or even a wizard that will aid him in configuring and using the component. A well-known case of this is the xxDataAdapter components, which allow you to do quite complex manipulation of the data access strategy. The following picture shows a component I developed that aids the user in checking bindings defined for a component, as well as editing them with a UI.
- Customize code generation: code generated for the InitializeComponent can be customized at will, up to the point where you can directly generate CodeDom statements for it. This means the complex component configuration can be translated into code (that will be compiled and very performant, therefore) that will be reloaded at run-time. And all the logic is encapsulated directly a separate class that acts as the CodeDomSerializer for the component, meaning that the component logic isn't even tied to the "serialization" format. You could even store the object's state in an XML file or anything else. Here's the code serialization for the component above:

- Through 3., participate in UI lifecycle: through the custom code that can be emited, a component can easily attach itself to relevant events in the UI containing it (i.e. a WebForm's Load or PreRender stages), and perform additional automatic processing, all without the user having to write a single line of code. In ASP.NET, this means for example, that a component can attach itself to the PreRender event, and add attributes and code to other controls on the page (for example, to setup required information for a client-side Javascript-based UI framework....). The component above, through the WebFormsAdapter connects the controller Init method with the page Init event, the controller RefreshModels method with the Load event, and the RefreshView method with the PreRender event.
- Revolutionary extension of existing components: we can even go further and implement AOP (Aspect Oriented Programmings) by directly adding "new" properties on other components/controls. This is the IExtenderProvider interface, which you could probably see applied in the Tooltip Windows Forms component. When you drop such a component on a WinForm, you see it in the component tray, and automatically all controls get a new property named after the name of the component. You can configure tooltip feature for all controls on the page on a single place, the component itself, and apply selective tooltip messages to each control you want.
The component shown above, the publisherControler, adds view-model mapping capabilities to all built-in and third-party controls on a page automatically:

- Component root designers and authoring: components can be composed graphically by dragging and dropping other components on a default design surface area. This results in RAD development of composite components by assembling the features of several constituent parts. You can even go and implement your own root designer, providing a more-compelling design-time experience. Simple attributes allow you to control the ToolBox, so that, for example, only certain components can be dropped on your control design surface. The following picture shows the root designer for the controller component, which allows you to only drop models on it:

- You can go even further and hook into the serialization process of other components, by using the IDesignerSerializationManager to register your own IDesignerSerializationProvider. This way, you could for example add arbitrary attributes to all controls on the page, *at design time*, that is, by emitting additional code for the InitializeComponent method. This makes for an ultimate AOP-enabler, combined with IExtenderProvider.
What's going on in Whidbey?
You would naturally expect for such a cool technology to be extender, further supported and exploited in the new version, right? Well, it turns out that the ASP.NET team is conciounsly stopping to support the feature in the new Web Forms designer.
One of the reasons they've given in the public bug database (if you haven't used MSDN Product Feedback yet, you definitely should!!!) is:
The web forms designer has changed to support only ASP.NET controls. It no longer supports component style controls.
There's a fundamental flaw in this reasoning. Components are *not* controls. They are not visual things, neither they are intended to be laid out together with the controls on the page, which DO need to be arranged for visually coherence and UI rendering. MS's comment on the bug goes on and says:
The primary reason for this change is the newer architecture provides a cleaner and more robust model for persisting controls in the page
Again, the reason is that they see everything as a control. What this means for you as a web app developer, is that instead of having a clean UI surface for laying out controls and designing the graphics aspects of your page, you get something like the following:
This is not an unreasonable example. You have a SiteMapDataSource datasource, for a navigation control, next you have an XmlDataSource probably for a treeview, and a SqlDataSource to render data on the GridView. Finally, as there's a WebPart, you need to drop a WebPartManager too. The WebPartManager is the extreme case, as you even have to drop it *before* any webpart in document order in order for it to work!!!!
Now, is it just me or this sounds a lot like a *HUGE* step backwards to the Visual InterDev days and before? It's clear to me that this means I'll be moving those "non-visual-controls" around so they don't mess with my page design experience. But it's worse than you think, you can't even set their top/left to -100!!! As they are not visual controls, you can't set any of the regular visual attributes :S. Ups!
The reason for deprecating this feature goes on:
We no longer rely on an "InitializeComponent" section, and there is not "tools generated" code ever. In the past we had many bugs around InitializeComponent not working correctly and the model was very brittle.
As I noticed before, being able to generate code from a component is a very powerful feature, and the ability to extend other controls from the outside (Aspect Oriented Programming, does it ring a bell?) is amazing, despite it wasn't publicized enough. Now, if there are bugs around the InitializeComponent method, the reasonable thing to do seems to be to go fix them, don't you think?
I complained this is a breaking change on ASP.NET v2, but they say:
You can still use components within a webform, however you have to do so in code, and the tray is not supported. You can still used components within classes in your web project however. To do so you can create a class that inherits from IComponent and place it in the code directory. You should then be able to open that class using the component designer and place components on it.
So, in order not to break existing apps, they just left the runtime support, but removed the design-time experience on WebForms. What's important to realize, though, is that the design-time experience, and the aids they represent to the users is that makes components so compelling. Building applications by composing blocks (components) into bigger components (i.e. dropping models on controllers, and controllers on pages) is just what some MS architects have been preaching, yet we have to see the ASP.NET team deprecating one of the most revolutionary steps in that direction.
And just in case I didn't stress it enough: ASP.NET Controls are obviously an ASP.NET-only technology, unlike Components, which can be used without changed in both WebForms and WinForms!!!
Call to action
It's not too late. Many developers already voted on the bug to keep the feature. We're not still at Beta2, so I believe if we put enough preasure, we may be lucky enough to get it back.
Go to the MSDN Product Feedback bug page and vote NOW. Otherwise, don't complain next year if you see this feature missing!
The usual approach to custom role-based security using forms authentication
(i.e. roles and users fetched from a database) on web apps is the
following:
protected void Application_AuthenticateRequest(Object sender, EventArgs e)
{
// Only replace the context if it has already been handled
// by forms authentication module (user is authenticated)
if (Context.Request.IsAuthenticated)
{
string roles[];
// Fetch roles from the database somehow.
// Reuse the identity created by Forms authentication.
GenericPrincipal ppal = new GenericPrincipal(
Context.User.Identity, roles);
Context.User = ppal;
}
}
There's one *huge* drawback to this approach, and it's that it will hit the
database on every single request! So, the proposed improved solution is:
protected void Application_AuthenticateRequest(Object sender, EventArgs e)
{
if (Context.Request.IsAuthenticated)
{
// Retrieve user's identity from context user
FormsIdentity ident = (FormsIdentity) Context.User.Identity;
// Retrieve roles from the authentication ticket userdata field
string[] roles = ident.Ticket.UserData.Split('|');
// If we didn't load the roles before, go to the DB
if (roles[0].Length == 0)
{
// Fetch roles from the database somehow.
// Store roles inside the Forms ticket.
FormsAuthenticationTicket newticket = new FormsAuthenticationTicket(
ident.Ticket.Version,
ident.Ticket.Name,
ident.Ticket.IssueDate,
ident.Ticket.Expiration,
ident.Ticket.IsPersistent,
String.Join("|", roles),
ident.Ticket.CookiePath);
// Create the cookie.
HttpCookie authCookie = new HttpCookie(
FormsAuthentication.FormsCookieName,
FormsAuthentication.Encrypt(newticket));
authCookie.Path = FormsAuthentication.FormsCookiePath + "; HttpOnly; noScriptAccess";
authCookie.Secure = FormsAuthentication.RequireSSL;
if (newticket.IsPersistent)
authCookie.Expires = newticket.Expiration;
Context.Response.Cookies.Add(authCookie);
}
// Create principal and attach to user
Context.User = new System.Security.Principal.GenericPrincipal(ident, roles);
}
}
The new version only goes to the DB once. It also uses the same encryption
features of forms authentication, as well as its ticket and cookie. A huge
performance boost, that's for sure.
Thanks to Hernan
for pointing this out while reviewing the security chapter of
my last book.
I'm reading PAG guide on Improving .NET Application Performance and Scalability (a must-read for every .NET developer), and I noticed they missed one of the most interesting and useful state management features ASP.NET introduced, the one I call transient state. This is the state that lives in HttpContext.Items, which only lasts for the duration of the current request, hence its characteristic of "transient". It's really awesome because you can pass information between modules, pages and controls with it, and completely avoid Session state. It's quickly discarded as soon as the current request has finished processing, so it doesn't impose any of the drawbacks you need to care about with Session.
In my experience, a combination of HttpContext.Items and the Cache API almost completely removes the need to use Session at all. And this is a good thing, as you're also avoiding server affinity resulting from inproc session state (the only one that performs well, BTW).
Too bad it didn't make into that excelent guide :(
Please, make sure these words get deep in your mind the next time you write an ASP.NET application:
If you're using Response.Write, you're a dreadful citizen of the ASP.NET world.
As my friend
Victor said, "Response.Write is there just for compatibility reasons and for old script programmers to not feel lonely".
An app written in such a way will not only be difficult to maintain and evolve, it will be almost impossible to customize (specially its layout), will never catch up with the upcoming mobile features and just hurts the eye.
Everytime I see a
Response.Write, and specially if it's not even kind enough to use
HtmlTextWriterTag,
HtmlTextWriterAttribute and
HtmlTextWriterStyle, the developer who wrote it is instantly removed from my in-memory list of good ASP.NET programmers.
Bottom line: you should always design your web apps as reusable components and user or custom controls, so that they can be easily rearranged, styled and plugged into existing apps.
Rob Howard wrote the
second part on the provider design pattern they are using in Whidbey, and
how to implement it in v1.x. An interesting reading. First of all, I'm
really amazed at how open these guys are to good feedback from the community.
Rob even dedicated a paragraph named "Extending configuration" that explains
why they chose a NameValueCollection for provider
initialization over an XmlNode, as
I suggested (I'm sure other did too, it's a pretty obvious thing to ask).
I really don't share the feeling that a NameValueCollection is
*sooo much* easier than an XmlNode and its added flexibility, but
at least I understand now why they did so: they expect complex providers to
have their own section handler with all the information they need to work,
which makes perfect sense!
There's a major performance issue in the implementation he suggests for v1.x,
though, that has to do with the actual creation of the specific provider
instance. There's a sort of mess in the naming and wording when this
feature is explained. The article says:
When calling routines on the Membership class, internally it
will always forwards those calls to an instance of the MembershipProvider—first
creating an instance of MembershipProvider using a factory method, Instance(),
and then calling the appropriate base class method on the retrieved instance.
Well, from the naming point of view, if Instance() is employed as a factory
method, it should be called CreateProvider() or something like that, to denote
that an instance will be created each time the method is called. And here comes
the confusion, because Instance() more closely resembles the Singleton pattern
rather than the Factory Method. If you think about it, there's no reason why we
should instantiate a new membership object all the time. Not even the dynamic
nature of providers justify this, because switching providers in the config
file will cause an app restart anyway, loading the appropriate one afterwards.
And this is even more important than a mere wording because instantiating the
provider dynamically requires using reflection. The abbreviated method shown in
the article is:
public static MembershipProvider Instance() {
// Use the cache because the reflection used later is expensive
...etc...
// Load the configuration settings
object[] paramArray = new object[1];
paramArray[0] = membershipProvider.Attributes["connectionString"];
return (MembershipProvider)( ((ConstructorInfo)cache[cacheKey]).Invoke(paramArray) );
}
Note that by caching only the constructor information, you're not earning much
anyways. You end up using reflection at each method call anyway. So, if you
convert this method from a factory method into a singleton, you directly cache
the provider instance you create the first time the method is accessed.
Furthermore, I'd directly move this singleton instance creation to the
Membership (or similar for other provider-enabled features) altogether:
public class Membership
{
static MembershipProvider _instance;
static Membership()
{
// Get the names of the providers
MembershipConfiguration config = MembershipConfiguration.GetConfig();
// Read the configuration specific information for this provider
Provider provider = (Provider) config.Providers[config.DefaultProvider];
// The assembly should be in \bin or GAC
try
{
Type type = Type.GetType( provider.Type );
_instance = (MembershipProvider) Activator.CreateInstance( type );
// Initialize the provider with the attributes.
_instance.Initialize( provider.Name, provider.Attributes );
}
catch (Exception e)
{
throw new Exception("Unable to load provider", e);
}
}
public static bool Validate( string username, string password )
{
return _instance.Validate( username, password );
}
public static void CreateUser( string username, string password )
{
return _instance.CreateUser( username, password );
}
}
You may have noticed that the original method in the article wrongly
calls a special constructor passing a specific hardcoded attribute,
"connectionString":
paramArray[0] = membershipProvider.Attributes["connectionString"];
// Special ctor?!
return (MembershipProvider)( ((ConstructorInfo)cache[cacheKey]).Invoke(paramArray) );
It's obvious that by doing so the Instance() method is no longer
generic, as it's expecting a provider to implement a specific ctor overload and
receive a connection string! What if I have an XmlMembershipProvider?
Given the base ProvideBase class all providers must implement, and
what is explained in the article it makes much more sense to use the ProviderBase.Initialize
method for provider initialization, as I did in the static ctor above:
Type type = Type.GetType( provider.Type );
_instance = (MembershipProvider) Activator.CreateInstance( type );
// Initialize the provider with the attributes.
_instance.Initialize( provider.Name, provider.Attributes );
Anyway, it's good that we're having these discussions. The ASP.NET community
needs these concepts to turn web applications into well architected solutions,
leaving the ASP spaghetti programming style behind once and for all.
A couple weeks ago Rob Howard
(from the ASP.NET team)
announced the "disclosure" of the
Provider Design Pattern they are using in Whidbey ASP.NET (v2).
I've got a couple complaints with this implementation:
While the first two are a matter of taste in the end, the last
one should be fixed promptly. I didn't hear any voice complaining,
however. Am I the only one envisioning complex providers with the need to
configure themselves with hierarchical XML information? It's all too common
everywhere!
You want a a concrete example? Here it goes:
What if I develop a provider that implements automatic DB schema installation
and migration? My super provider could allow the full DB schema to be specified
in the configuration itself:
...other tables...
The provider can detect the presence of the schema and create it automatically
if necessary. I could even go as far as saying that it could even define
through configuration the way to migrate a schema if it's incompatible, or
whatever.
Another one: maybe my provider uses a webservice. I may need to pass complex
information to the provider, such as credentials, proxy information, SOAP
message skeletons, or whatever. None of this is possible with a NameValueCollection.
VGA found a recurrent problem most developers and users of the MS Calendar
control seem to have, namely, its poor integration with CSS styles. Being an
OOP fan, I clearly see an easy way to solve this problem. Inherit
Calendar and change its behavior! That's the cool thing about .NET and
the new ASP.NET. It's all too easy:
public class UnStyledCalendar : Calendar
{
protected override void Render(HtmlTextWriter writer)
{
base.Render (new NonStyleWriter( writer) );
}
}
Cool, huh? The "secret", of course, is the derived writer, which simply
implements a passthrough HtmlTextWriter descendant which skips
calls to the virtual AddStyleAttribute and WriteStyleAttribute
methods:
private class NonStyleWriter : HtmlTextWriter
{
HtmlTextWriter _writer;
public NonStyleWriter(HtmlTextWriter innerWriter) : base(innerWriter.InnerWriter)
{
_writer = innerWriter;
}
public override void AddAttribute(HtmlTextWriterAttribute key, string value)
{
_writer.AddAttribute(key, value);
}
// Passthrough all other methods
public override void AddStyleAttribute(HtmlTextWriterStyle key, string value)
{
// Do nothing here. We don't want style attributes!
}
public override void AddStyleAttribute(string name, string value)
{
// Do nothing here. We don't want style attributes!
}
public override void WriteStyleAttribute(string name, string value)
{
// Do nothing here. We don't want style attributes!
}
public override void WriteStyleAttribute(string name, string value, bool fEncode)
{
// Do nothing here. We don't want style attributes!
}
}
What you get is a calendar without ANY style="" attributes
whatsoever.
I leave the task of putting this into a library, copying the XSD from the MS
Calendar, installing it under the appropriate VS folder to get intellisense,
and toolbox item attribute to VGA, which excels in the matter ;). The code can
be downloaded from the
ASPNET2 Incubator
Some time ago I complained about a naive approach to the subject suggested in an
MSDN article. It looks like I was
not the only one thinking along the lines of signed licencing files :o)
Update: another product also exists, which is more powerful and mature, judging by its features description and blog comments...
Sometimes you need low level information about the current request in a web
application, such as the IP address of the physical network adapter the request
came through (cool in clustered multi-NIC servers), or some other weird stuff
you can't find in the higher-level view provided by HttpRequest,
HttpResponseand friends.
Luckily, the HttpContext implements IServiceProvider,
which means you can ask for services with the following code:
IServiceProvider provider = (IServiceProvider) HttpContext.Current;
// Get the request
HttpRequest util = (HttpRequest)
provider.GetService(typeof(HttpRequest));
OK, I know... who on earth would use that instead of simply calling HttpContext.Current.Request???
Well, THE one thing you can get that there's absolutely NO other way of
getting, is the current
HttpWorkerRequest:
// Get the worker
HttpWorkerRequest wr = (HttpWorkerRequest)
provider.GetService(typeof(HttpWorkerRequest));
// Get the NIC address!!!!
string addr = wr.GetLocalAddress();
Another very cool use is to retrieve known header values. Usually, you just
get the header from the Request.Header collection by its name:
// Would return "Keep-Alive" if enabled.
string cn = Request.Headers["Connection"];
// Would return "gzip, deflate" for example.
string enc = Request.Headers["Accept-Encoding"];
but that's prone to errors, and you have to sort of guess the casing, etc. This is the cool way:
// Get the worker
HttpWorkerRequest wr = (HttpWorkerRequest)
provider.GetService(typeof(HttpWorkerRequest));
string cn = wr.GetKnownRequestHeader(HttpWorkerRequest.HeaderConnection);
string enc = wr.GetKnownRequestHeader(HttpWorkerRequest.HeaderAcceptEncoding);
Have a look at the
class members
, there are quite a few interesting things, now that you can call them ;)...
and use them NOW, before they regret making such a beast available...
Non-visual components (those staying in a zone at the bottom of a webform -and also WinForms-) are SO cool: they have rich design-time features (designers, editors, full-blown editing UIs) that are UI-independent (can be used on windows and web forms, think of Dataset, SqlConnection, EventLog, etc.), can provide extensility to preexistent controls through IExtenderProvider, can interact with VS.NET services, generate code for the code-behind InitializeComponent, hook custom serializers, etc., etc.
Being SO cool, and having developed a couple products (even a yet-another-MVC) that heavily rely on them, it was more than surprising (to say the least) to find that they no longer appear at design-time in Whidbey Web Developer!! Everything seems to work (still) at run-time, but no design-time support!! So all the code serialization, designers and editors are completely useless now :S.
I honestly hope this is only a matter of early bits and time constraint, and that they are not obsoletting a feature introduced just a couple years ago (and a very good and usefull one indeed).
I'd think more than twice before implementing the
Encrypted Licence Scheme
proposed by Nikhil Kotari. He's proposing to embed the bytes of the key in
the assembly itself, and use that as the encryption (for the generator) and decryption (at run-time).
Any decent programmer knows that dumping the IL code with ILDASM will easily expose those bytes as follows (even in
Release mode compilation):
.data D_00002408 = bytearray (
35 46 42 32 38 31 46 36) // 5FB281F6
Now you can write a trivial console app to hack the expiration limit proposed in the same document, for example:
[STAThread]
static void Main(string[] args)
{
byte[] encryptionKeyBytes = ASCIIEncoding.ASCII.GetBytes("5FB281F6");
string license;
DESCryptoServiceProvider des = new DESCryptoServiceProvider();
des.Key = encryptionKeyBytes;
des.IV = encryptionKeyBytes;
// Read the encrypted file.
ICryptoTransform desDecryptor = des.CreateDecryptor();
using (FileStream fs = new FileStream(@"..\..\LicensedControls.EncryptedLicensedLabel.lic", FileMode.Open))
{
using (Stream crypt = new CryptoStream(fs, desDecryptor, CryptoStreamMode.Read))
{
byte[] licbytes = new byte[fs.Length];
crypt.Read(licbytes, 0, licbytes.Length);
license = UTF8Encoding.UTF8.GetString(licbytes);
}
}
Console.WriteLine("Decrypted licence: {0}", license);
// Spoof the license with a bigger limit.
license = String.Concat(
license.Substring(0, license.LastIndexOf(".") + 1),
";", Int32.MaxValue);
Console.WriteLine("Hacked licence: {0}", license);
// Persist it encrypted again.
ICryptoTransform desEncryptor = des.CreateEncryptor();
using (FileStream fs = new FileStream(@"..\..\LicensedControls.EncryptedLicensedLabel.lic", FileMode.Create))
{
using (CryptoStream crypt = new CryptoStream(fs, desEncryptor, CryptoStreamMode.Write))
{
byte[] licbytes = UTF8Encoding.UTF8.GetBytes(license);
crypt.Write(licbytes, 0, licbytes.Length);
crypt.FlushFinalBlock();
}
fs.Flush();
}
Console.WriteLine("Finished");
Console.ReadLine();
}
Voila! Now your licensed control can be used almost forever without expiration
(I could have used Int64.MaxValue to get even more, but you get the idea).
I believe we have to come up with a better solution. Maybe signing the license
file with the assembly private key (sn.exe-generated), and then checking its
integrity with the assembly public key... what about building something like
that right inside ASP.NET 2.0? That would really great!
This is such a frequent question, that I thought I’d better spend some time outlining a
customizable and versatile solution so that it can be reused in future scenarios.
Often, binary resources such as employee pictures, office documents in a document management
system, and others, are stored in a database. Now the issue is how to pull that information
out of it and show it using ASP.NET. One way to solve this problem is creating a dummy ASP.NET
page that simply uses Response.BinaryWrite() to output the binary field brought by the DB query,
as is explained in an ASP Alliance
article. However, you don’t get encapsulation and reusability, having to resort to copy/paste
as new projects need such a feature.
My advice is to always use a custom IHttpHandler that serves these binary resources.
Of course this is not a new idea, I'm just putting it here so I can refer to the countless
persons that asked me.
You have to map a path to your handler in the Web.config file, and to avoid having to modify the IIS
extensions mapping, you should use one of the built-in extensions that are already mapped to ASP.NET at installation time:
.ashx or .axd. It's always better to use an specific "file name" for your handler, to avoid interfering with the ASP.NET
built-in handlers. Such a handler should be configured in the Web.config as follows:
<configuration>
<system.web>
...
<httpHandlers>
<add verb="GET" path="getresource.axd" type="NMatrix.Web.BinaryResourceHandler, NMatrix.Core" />
</httpHandlers>
From now on, each request sent to the "file" getresource.axd will be passed to our handler.
The ".ashx" extension could have been used too: it's already mapped in IIS to the ASP.NET ISAPI filter,
it doesn't affect the normal ASP.NET execution, and it was conceived as the natural extension to
use by so-called "web handlers" (see
other articles).
However, that extension is usually applied to files that look like .aspx with inline server-side code with an
@ webhandler directive. That's why I prefer the "axd" extension.
We map only the GET verb as it's the only one we will need to retrieve resources. This
could easily be extended by allowing the POST verb meaning a new resource should be stored.
I'll leave that as homework for the reader. Mostly, uploading resources is a more complex process that
involves authorization at least, maybe even a full document management system.
The handler will need two parameters: the resource ID and the connection string to the repository. The
first one will be provided by the calling client, as a query string value. The later is stored in the
Web.config for simplicity:
<configuration>
<appSettings>
<add key="connection" value="Data Source=.\NetSdk;Initial Catalog=Resources;User Id=sa;Pwd=;" />
</appSettings>
To make the storage flexible, the table storing the resources will also contain a ContentType to
allow the storage of arbitrary types. Now the handler code:
using System;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using System.Web;
namespace NMatrix.Web
{
/// <summary>
/// Serves binary resources stored in a database.
/// </summary>
/// <author>Daniel Cazzulino</author>
public class BinaryResourceHandler : IHttpHandler
{
#region Ctor & Vars
//Key used in Web.config
public const string ConnectionStringKey = "connection";
//Holds the DB connection
private static string _connectionstring;
//Size of the chunk to read from the DB
private const int ChunkSize = 1024;
static BinaryResourceHandler()
{
_connectionstring = ConfigurationSettings.AppSettings[ConnectionStringKey];
if (_connectionstring == null || _connectionstring.Length == 0)
throw new ArgumentException("A 'connection' attribute must be provided to the handler.");
}
#endregion Ctor & Vars
#region IHttpHandler Members
public void ProcessRequest(HttpContext context)
{
string id = context.Request.QueryString["id"];
if (id == null || id.Length == 0)
throw new ArgumentException("An 'id' query string value must be specified.");
using (SqlConnection cn = new SqlConnection(_connectionstring))
{
SqlCommand cmd = new SqlCommand("SELECT ContentType, BinaryData FROM Resources WHERE ResourceId=@id", cn);
cmd.Parameters.Add("@id", SqlDbType.VarChar, 50);
cmd.Parameters["@type"].Value = id
cn.Open();
//CommandBehavior.SequentialAccess avoids loading the entire BLOB in-memory.
SqlDataReader r = cmd.ExecuteReader(CommandBehavior.SequentialAccess);
if (r.Read())
{
context.Response.ContentType = r.GetString(0);
byte[] buffer = new byte[ChunkSize];
long idx = 0;
long size = 0;
//Write the BLOB chunk by chunk.
while ((size = r.GetBytes(1, idx, buffer, 0, ChunkSize)) == ChunkSize)
{
context.Response.BinaryWrite(buffer);
idx += ChunkSize;
}
//Write the last bytes.
byte[] remaining = new byte[size];
Array.Copy(buffer, 0, remaining, 0, size);
context.Response.BinaryWrite(remaining);
}
}
}
/// <summary>
/// This instance is freely reusable.
/// </summary>
public bool IsReusable
{
get { return true; }
}
#endregion IHttpHandler Members
}
}
The code is straightforward. The only tip is that by using CommandBehavior.SequentialAccess,
the SqlDataReader can read the binary data in chunks, avoiding to load it completely in-memory (thanks Pablo
Castro!).
A client application performing uploads could simply have a file upload HTML control
(with runat="server" to allow our code to access the Request.Files collection)
and with the following code could simply save arbitrary files to the database:
private void btnUpload_ServerClick(object sender, System.EventArgs e)
{
using (SqlConnection cn = new SqlConnection(ConfigurationSettings.AppSettings[
NMatrix.Web.BinaryResourceHandler.ConnectionStringKey]))
{
SqlCommand cmd = new SqlCommand("INSERT INTO Resources (ContentType, BinaryData) VALUES (@type, @data)", cn);
cmd.Parameters.Add("@type", SqlDbType.VarChar, 50);
cmd.Parameters.Add("@data", SqlDbType.Image);
cmd.Parameters["@type"].Value = txtContent.Text;
byte[] data = new byte[Request.Files[0].InputStream.Length];
//Trunc the stream length. Nobody will be able to send Int.MaxValue bytes (around 2Gb!)
Request.Files[0].InputStream.Read(data, 0, (int) Request.Files[0].InputStream.Length);
cmd.Parameters["@data"].Value = data;
cn.Open();
cmd.ExecuteNonQuery();
}
}
The ContentType field has a purpose: if someone specifies application/msword or
application/msexcel (or any other content type understood and handled specially
by the browser), IE will automatically instantiate the appropriate Office application inside
the browser window to open the incoming "file" (stream, more properly).
To refer to a resource of type image/jpg from an <img> HTML tag, we could use:
<img alt="Dynamically served image" src="getresource.axd?id=3">
To directly open a Word document from the server, we could simply point IE to the same handler passing
its id.