Framework Madness!

And other adventures C# and asp.net …

Posts Tagged ‘asp.net mvc

Asp.net MVC 2: Creating a SimpleValuesModelBinder

leave a comment »

I have been thinking about what it would take to make a custom model binder for the PayPal IPN service the past week or so, and tonight I finally had the chance to look into it. The goals is simple – I just want to pass the IPN form values to a model that has properties with different names. I don’t want to do any custom model binding, perhaps a small bit of string parsing but that’s about it.

I looked into model binding at the MSDN library, Steve Sanderson’s book, and the TekPub MVC series, they all were good, but what I wanted to do was simple. On thing I did get out of it was that I would need both a custom ModelBinder implementing IModelBinder and possibly a custom ValuesProvider as well.

Finally, I looked into the MVC source for the DefaultModelBinder to see how it worked and came up with pure gold. Here is the basic premise of the solution:

  • Create an abstract model binder class that uses the DefaultModelBinder class to do its work.
  • Leverage the NameValueCollectionValueProvider class to provide simple Key/Value pairs to the DefaultModelBinder .
  • Create a custom copy of the supplied ModelBindingContext that connects the binder and provider together.

Here’s the code with comments:

Code Snippet
//this allows for supplying values using a simple key/value pair collection
    ////all complicated binding set up is abstracted
    //DefaultModelBinder is used for ModelBinding
    //NameValueCollectionValueProvider is used as the ValueProvider
    public abstract class SimpleValuesModelBinder : IModelBinder
    {

        protected abstract void AppendValues(ControllerContext controllerContext, NameValueCollection collection);

        public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
            //first we want to call AppendValues
            //the collection is supplied to the SimpleValuesProvider
            //we use the NameValueCollectionValueProvider because it uses key/value pairs
            var collection = new NameValueCollection();
            AppendValues(controllerContext, collection);

            //create a custom binding context
            //we pass thru properties except the value provider
            //we use the new TestValueProvider here
            var customContext = new ModelBindingContext()
            {
                ModelMetadata = bindingContext.ModelMetadata,
                ModelState = bindingContext.ModelState,
                PropertyFilter = bindingContext.PropertyFilter,
                ValueProvider = new NameValueCollectionValueProvider(collection, CultureInfo.CurrentCulture)
            };

            //pass our custom binding context the default binding model and bind
            return new DefaultModelBinder().BindModel(controllerContext, customContext);

        }
    }

 

Creating a custom model binder from this class is very simple. Here is a simple class:

Code Snippet
public class TestModel
    {
        public string Value { get; set; }

        public DateTime Current { get; set; }
    }

… and here is custom binder using the abstract class above:

Code Snippet
public class TestModelBinder : SimpleValuesModelBinder
    {

        protected override void AppendValues(ControllerContext controllerContext, NameValueCollection collection)
        {
            collection["Value"] = Guid.NewGuid().ToString();

            collection["Current"] = DateTime.Now.ToString();
        }
    }

The resulting custom model binder is very simple. All you have to do is override one method, AppendValues, and your done. In this case I am supplying arbitrary values as a test, but you can leverage any values you want from the ControllerContext parameter.

Of course set up is easy too, ASP.net MVC allows several ways to do this. For a test, I’ll just apply to a parameter in an action method.

Code Snippet
public ActionResult Index([ModelBinder(typeof(TestModelBinder))]TestModel Test)
        {
            return Content(string.Format("Value: {0}; Current: {1}",Test.Value,Test.Current));
        }

 

And the the less than glamorous result:

image

So, if your looking to do some simple value parsing this may help.

Advertisements

Written by Lynn Eriksen

August 22, 2010 at 4:16 am

Posted in Uncategorized

Tagged with

Global AJAX Request Error Display for Asp.net MVC 2

leave a comment »

 

So you thought you might like to,
Go to the show.
To feel the warm thrill of confusion,
That space cadet glow.
Tell me is something eluding you, sunshine?
Is this not what you expected to see?

 

Ever get that kind of feeling when trying to debug server side request errors using AJAX (MS AJAX or jQuery) in MVC. I mean, on a normal posts that fails you get the nice yellow error screen that says “Hey you …” and “Bring on the (Stack Trace)!” and makes your wonder “Is there anybody out there?”. We’ll no more. Here’s a basic script you can just hook up while building/debugging your app that if you get a server side error making an AJAX request you’ll get the same effect as a full post back.

 

Code Snippet
/// <reference path="../Common/jquery-1.4.1-vsdoc.js" />
/// <reference path="../Common/MicrosoftAjax.js" />

$(document).ready(function () {

    //replace the screen with the response error

    //jQuery —————————————————–
    $(document).ajaxError(function (event, request, settings) {

        $(document.body).html(request.responseText);

    });

    //MS AJAX —————————————————-
    function OnWebRequestComplete(executor, eventArgs) {

        if (executor.get_statusCode() === 500) {

            $(document.body).html(executor.get_responseData());
        }
    }

    Sys.Net.WebRequestManager.add_completedRequest(OnWebRequestComplete);

});

Written by Lynn Eriksen

March 30, 2010 at 12:13 am

Posted in Uncategorized

Tagged with ,

Strong-Typed Routes with Asp.net MVC 2 Preview 2

with one comment

Update 3/28/2010

Didn’t realize it had been so long since I have created this post. It appears that the MVC Futures team has stepped up and published a set of strong-typed route extensions in recent build. You can find a link to these on the MVC Page on CodePlex.

I’ll be publishing a set of extensions I have made to work with these in a few days based on ideas in the work below. Therefore, I am removing the download link.

 


Last weekend I enthusiastically went on and on about using Strong-Typed routes in MVC 2 Preview 2 based on Goran Gagic’s elegant sample. And so I have built on his code and I have something to share.

Download Sample Project Here

I am going to dive more into usage than working internals, so let’s get underway.

Project Configuration

I have made some configuration changes to the sample project to better illustrate the feature set and make usage very convenient when constructing views. First, I have added a few namespaces to the web.config as you can see in the image below:

strong-typed-routes web-config namespaces

The namespace ‘MVC2_TypedRoutes.TypedRoutes’ (the ‘TypedRoutes’ folder) contains the extensions and support classes for strong-typed  route value creation. Secondly, I have added an additional routes in the global.asax as show below:

strong-typed-routes global-asax extra-routes

Both of these routes utilize the TypedRoutesController exclusively, but differ in their signature using the ‘_RouteName’ value. I have also set up a simple controller that will be used to demonstrate the features. Let’s look at the controller:

strong-typed-routes typed-routes-controller

There are several attributes applied here that are leveraged by the strong-typed route extensions. Let’s review them:

  • RouteActionAttribute

    This attribute has a single property named ‘PassThru’ that allows for a entering a comma separated list of route value names to be passed thru when creating routes. This attribute can be applied to a class or method.

    In the sample it is applied to the class, so all strong-typed routes created for the TypedRoutesController will have the ‘_RouteName’ route values passed along when generating a route call.

  • RouteValueAttribute

    This attribute allows for specifying a format for the values in the route (especially handy for dates), default values and if the parameter is ignored in creating the route. It can be applied to parameters or properties.

    In the sample as applied to the ‘Date’ parameter in the ‘Sample1’ action method it specifies a default DatetTime of Jan 1, 2000. If the date value submitted when creating the strong-typed route in an Html.ActionLink<Controller> extension matches the default, it will not be passed to the resulting route. Additionally, the ‘Format’ value is specified and a route friendly format for the date parameter will be used.

Additionally, the ‘Sample2’ action method has the MVC BindAttribute applied and this will be used by the strong-typed route extensions as well.

Project Usage

The sample get’s right to the point, creating three strong-typed routes inside the HomeController ‘Index’ view to the TypedRoutesController. Let’s take a look at the ActionLink<Controller> calls and the resulting routes.

Sample ActionLink Route 1

strong-typed-routes sample-1

Here’s the run down on using the strong-typed ActionLink:

  • It’s a generic method – so you have to specify the controller
  • The first parameter is simple – the title for the action link
  • The second parameter is an expression based call to a method on the TypedRoutesController, in this case ‘Sample1’. (Notice the date supplied is the same as the default specified by the RouteValueAttribute.)
  • The third parameter is something I have not mentioned yet. This is a expression call that leverages a fluent-interface object that allows you to easily set route values, route value formats, and html attributes. Let’s take a look at the signature of the fluent-interface object:

    strong-typed-routes action-link-settings   

    As you can see you can  apply single or multiple attributes, formats or values. And for attributes I used the JQuery ‘Attr’ for html attributes. (Important note: any formats or route values specified here will override those specified by by the RouteValueAttribute applied to the action method or the method expression provided by calling the Html.ActionLink<C> extension or Url.Action<C> extensions. Phew!)

    In this case we are submitting a route value for ‘_RouteName’ of ‘TypedRoutes1’.

Here is the resulting route:

/TypedRoutes1/Sample1 

Here is a brief run down:

  • The Date RouteValueAttribute default is matched so the value from the ActionLink extension is not passed along in the route.
  • The route ‘TypedRoutes1’ is called specified by supplying the appropriate ‘_RouteName’ value.

Sample ActionLink Route 2

 strong-typed-routes sample-2

Let’s look at the differences:

  • We are calling the same action method as in sample 1 above, but this time we are specifying the current time.
  • This time we are submitting a route value for ‘_RouteName’ of ‘TypedRoutes2’.

Here is the resulting route:

/TypedRoutes2/Sample1?Date=2009-10-18

Notice it correctly chose the ‘TypedRoutes2’ route and submitted a date value formatted as specified by the RouteValueAttribute applied to the method Date parameter.

Sample ActionLink Route 3

strong-typed-routes sample-3

Here is the brief run down:

  • This sample calls a different action, one that takes a complex object.
  • Like sample 2above we are submitting a route value for ‘_RouteName’ of ‘TypedRoutes2’.
  • Also, if we look at the controller it has a BindAttribute applied with a prefix. This will be used in formatting values in the route.
  • Also we are specifying a custom format for ‘TestObject.Date’.

Here is the resulting route:

/TypedRoutes2/Sample2?TestObject.Name=Sample 2 Link&TestObject.Date=2009-10-18

 

That’s It for Now

But before I go a few additional notes:

  • This was compiled for MVC 2 Preview 2 but can easily be made to work under MVC 1 by removing the ‘ToHtmlString’ method calls which are new in MVC 2 Preview 2.
  • The RouteValueAtrribute can be applied to properties in complex objects being used as action method parameters, but I have not made extensive testing of this.
  • There are additional views in the sample project that shows off the subtle power of using the ‘PassThru’ property of the RouteActionAttribute.
  • There are also Action methods of the Url helper for use in view or controllers.

Written by Lynn Eriksen

March 28, 2010 at 11:53 am

Posted in Uncategorized

Tagged with

Things that make you say “Duh!”: Asp.net MVC 2 Controller base classes.

leave a comment »

I’ve been playing around with Asp.net MVC 2 since last fall (and now on the awesome VS 2010RC) and I asked my self “Can I do a base class for a Controller and have the public methods work?”

Answer: Yep. It works. Even method overrides.

Duh.

Written by Lynn Eriksen

March 11, 2010 at 11:17 am

Posted in Uncategorized

Tagged with

Asp.Net MVC 2 Series at TekPub

leave a comment »

TekPub is an interesting idea in that it’s actually totally conventional: if you can present the material well enough you should get paid. In this case, I agree. Rob and Steven have done a very nice job so far presenting not only the main features but also the ‘tricks’ that can save you time and frustration. I recommend the series:

http://tekpub.com/preview/aspmvc

Written by Lynn Eriksen

February 21, 2010 at 9:21 pm

Posted in Uncategorized

Tagged with

StructureMap 2.6.1 – Looking for Documentation? Here are a few helpful tips.

with 7 comments

I have started to use StructureMap in a new project I’m incubating here at home. Version 2.6x is VERY easy to use, but it is not documented. I think Jeremy has done a very nice job making StructureMap much more approachable. But there has been so much change that most of the documentation and community helps you’ll find are now obsolete. I have only one complaint, and that is that the new version is not 3.0. With this many changes it should be.

So, back to the main point. The only documentation I’ve found is by looking over Jeremy Miller’s recent blog posts, a few video presentations he’s made, and the Google news group. Here is what I have found:

1) Usage should be scoped to ‘ObjectFactory.Container’. This will become convention moving forward. 
(See Figure 1)

2) If you use the ‘Initialize’ method you wipe the container. So go with ‘Configure’ if you want to progressively set up you IOC mappings.
(See Figure 1, 2)

3) Most mappings can now be made using the ‘For’ and ‘Use’ expressions. ‘Use’ is very powerful and simple with it’s overloads, with them you can specify a return type, return an object instance, and more.
(See Figure 1, 2)

4) You can create a scoped container. This creates an instance copy of ‘ObjectFactory.Container’ and applies a Profile mapping to it. So there are no worries about caching scenarios, HttpContext use, etc.  And the scoped container implements IDisposable so you can leverage a ‘Using’ block to force it to clean up.  
(See Figure 3)

5) The syntax for creating a Profile is a bit cleaner.
(See Figure 2)

 

Code Snippet
  1. ObjectFactory.Container.Configure(c => c.For<IModulesContext>().Use<ModulesContext>());

Figure 1

Code Snippet
  1. ObjectFactory
  2.     .Container.Configure(i =>
  3.   {
  4.       i.Profile(_StorageProfile, p => p.For<IStorageContext>().Use(new StorageContext("~/_Storage")));
  5.   });

Figure 2

Code Snippet
  1. using (IContainer Factory = ObjectFactory.Container.GetNestedContainer(routeProfile.ToString()))
  2. {
  3.     return Factory.GetInstance(controllerType) as IController;
  4. }

Figure 3

Written by Lynn Eriksen

February 21, 2010 at 9:13 pm

Posted in Uncategorized

Tagged with ,

Asp.net MVC – HandleUnknownAction in Controller

with one comment

Sorry I have been away so long. Work has been very busy and I have been doing a lot of planning for new projects, reading, rebuilding the notebook and trying to endure winter. Needless to say I have been away for a while.

So … I have started to look in building MetaWeblog support into an MVC project and have found a dearth of examples. So after doing some reading, testing, reflectoring, etc. I have decided to role my own. “Why not?” I figure.

The first thing I tried was to create a basic MetaWeblog action model and custom model binder. The model binder (which was easy to make) worked, but it didn’t solve the big problem – I want to create individual methods for each MetaWeblog RPC, and that wouldn’t cut it. I considered making a filter, but that wouldn’t work either. So the the next thing was to try to hack the controller, and that seems to work nicely.

One of the things the MVC team has done a nice job is keeping the architecture of the MVC platform simple and open. I started using reflector to find an easy access point to inject a change to action method called and sure enough I found it the ‘HandleUnknownAction’ of the Controller class. I’ll show an example and then explain:

Code Snippet
  1. public class UnknownController : Controller
  2. {
  3.  
  4.     protected override void HandleUnknownAction(string actionName)
  5.     {
  6.         if (!String.IsNullOrEmpty(actionName))
  7.         {
  8.             //set unknown routevalue
  9.             ControllerContext.RouteData.Values["UnknownValue"] = DateTime.Now.ToString();
  10.  
  11.             if (this.ActionInvoker.InvokeAction(this.ControllerContext, "UnknownAction"))
  12.             {
  13.                 
  14.  
  15.  
  16.                 return;
  17.             }
  18.         }
  19.  
  20.         base.HandleUnknownAction(actionName);
  21.     }
  22.    
  23.  
  24.     public ActionResult UnknownAction([DefaultValue("")]String UnknownValue)
  25.     {
  26.         return Content(String.Format("UnknownAction: {0} : {1}", RouteData.Values["action"],UnknownValue));
  27.     }
  28.     
  29.  
  30. }

The highlights:

  • So for a simple test I just wanted to redirect the action of the ‘actionName’ parameter existed. And unless you change the route defaults it’s ‘index’ – so we are good here. (The base method of HandleUnkownAction is simple – it just throws an Http error. )
  • Next I injected an new route value keyed as ‘UnknownValue’ and this matches a parameter on the ‘UnknownAction’ method I am going to call. (Yes! It does bind!’)
  • Last we call the ‘InvokeAction’ method on the ActionInvoker property of the controller. Important: you must return if the of the InvokeAction method succeeds. And the rest just works as if your calling a normal action method.
  • The results are simple. Here is an example:
    UnknownAction: Index : 1/14/2010 12:54:53 AM

So I am thinking that this would be a good basis for creating a MetaWeblog API handler using basic MVC conventions. I’ll provide more information as I get further along.

Written by Lynn Eriksen

January 14, 2010 at 1:05 am

Posted in Uncategorized

Tagged with ,