BusinessRx Community

Dedicated to the advancement of software, technology and the people who devote their lives to it.

Welcome to BusinessRx Community Sign in | Join | Help
in Search

BusinessRx Reading List

These blog entries are written by industry experts and leaders. We consider this content to be a good read for any software developer or web technologist.

May 2009 - Posts

  • May 30th Links: ASP.NET, AJAX, ASP.NET MVC, Visual Studio

    Here is the latest in my link-listing series.  Also check out my ASP.NET Tips, Tricks and Tutorials page and Silverlight Tutorials page for links to popular articles I've done myself in the past. 

    You can also now follow me on twitter (@realscottgu) where I also post links and small posts.

    ASP.NET

    AJAX

    • Automatically Minify and Combine JavaScript in Visual Studio: Dave Ward has a great article that describes how you can add a build command to Visual Studio that enables you to automatically compress and combine client-side JavaScript files.  This makes your pages load faster on the client and improves the perceived performance of your sites.

    • Client-side Data Binding in ASP.NET AJAX 4.0: Fritz Onion has a great article about the new client-side templating features of ASP.NET AJAX 4.0 (which you can download and use today in .NET 3.5 projects).  This enables powerful client data-binding scenarios against JSON based data.  Also check out Politian’s Blog to find some great tutorials on how to use it.

    ASP.NET MVC

    • Visual Studio NUnit Templates for ASP.NET MVC: The VS Web Tools team has released updated NUnit templates that work with ASP.NET MVC 1.0.  This enables you to automatically create a test project that uses NUnit instead of MSTest when you do a File->New Project and select the ASP.NET MVC 1.0 Project item.

    • Custom Route Constraints in ASP.NET MVC: Keyvan Nayyeriu has a nice post that discusses how to create a custom route constraint in ASP.NET MVC (one of the extensibility points in Simone’s list above).  You can use these to control whether a route rule is used or not, and they can enable some pretty rich routing scenarios.  Note that in addition to creating route constraint classes, ASP.NET MVC also supports using Regular Expressions and HTTP Method filters to constrain routes as well. Keyvan is the co-author with Simone of the Beginning ASP.NET MVC Book (free chapter available).

    Visual Studio

    Hope this helps,

    Scott

  • LIDNUG: Free Online Virtual Chat with Me Today

    LIDNUG (Linked .NET Users Group) is hosting an online chat with me today (Wednesday) from 11:30am to 1pm PST (Pacific Standard Time).  Anyone is free to join and the agenda topic will be open – so bring your questions!

    Click here to learn more about how to register and attend it.

    Hope to chat with you more then,

    Scott

  • Sending ELMAH Errors Via GMail

    ELMAH is a free, open source error logging system for ASP.NET created by Atif Aziz. This blog post assumes the reader is already familiar with using and configuring ELMAH. If this is not the case, refer to Simone Busoli's article, ELMAH - Error Logging Modules and Handlers for more information.

    One of ELMAH's most useful features is that it can automatically e-mail the details of a runtime error to a specified set of recipients. This feature allows developers to be notified immediately once a runtime error occurs. (ELMAH can also syndicate recent errors as an RSS feed and, with the release of ELMAH version 1.0, ELMAH can even tweet error details.) While I've used this feature many times in the past, I ran into some difficulties setting it up to send the error e-mails through GMail's SMTP servers. You can specify the SMTP settings directly in ELMAH's <errorMail> setting or you can define it in the <system.net> section, as described in Sending Email in ASP.NET. I typically use the <system.net> setting because I also use this information in my website and don't want to repeat it twice in Web.config. Consequently, my Web.config file looks similar to the following:

    <elmah>
        <errorMail
            from="..."
            to="..."
            subject="..."
            async="true"
        />
    </elmah>

    <system.net>
        <mailSettings>
            <smtp deliveryMethod="network">
                <network host="..." port="..." userName="..." password="..." />
            </stmp>
        </mailSettings>
    </system.net>

    The first challenge is that GMail's SMTP servers require SSL. However, you cannot specify SSL behavior through the <system.net> settings; rather, you have to do it when you instantiate the SmtpClient object, via its EnableSsl property. To instruct ELMAH to send e-mail via SSL you need to set the <errorMail> section's useSsl attribute to true, like so:

    <errorMail
        ...
        useSsl="true" />

    As of the time I am writing this blog post, this attribute is not shown in the sample Web.config file, so you wouldn't know it exists unless you examined ELMAH's source code.

    The second issue is that GMail's SMTP server uses port 587 instead of the standard port 25. I had correctly set the port number in the <system.net> section and believed I could then omit it from the <errorMail> section. However, I was wrong. If you omit the port from <errorMail> then ELMAH uses port 25. It does not turn to the <system.net> section and use the port number specified there.

    To remedy this you can do one of two things:

    • In <errorMail>, set the smtpPort attribute to the port you want to use.
    • In <errorMail>, set the smtpPort attribute to "0". Doing so will cause ELMAH to use the port defined per the <system.net> settings.

    With these changes my Web.config ends up looking like the following:

    <elmah>
        <errorMail
            from="..."
            to="..."
            subject="..."
            async="true"
            smtpPort="0"
            useSsl="true"

        />
    </elmah>

    <system.net>
        <mailSettings>
            <smtp deliveryMethod="network">
                <network host="smtp.gmail.com"
                            port="587"
                            userName="..."
                            password="..." />
            </stmp>
        </mailSettings>
    </system.net>

  • The Perfect Margarita

    I have finally found the perfect margarita recipe and I just had to share it:

    1 1/2 oz Patron Silver.

    1 1/2 oz Grand Marnier

    Combine those in a mixer with ice and then cut a lime in half and squeeze all the juice from half of the lime into the mixer. Put a dash of salt in the mixer. Shake it for about 20 seconds then pour. Delicious.

    Sweet and Sour and Sweetened Lime Juice is horrible and don't let it anywhere near your drink, otherwise you will end up with one of those horrible things they serve at most restaurants.

    -James

  • Iterating on an ASP.NET MVC Model Binder

    After my last post on model binding tips I’ve had a number of questions about the nuances of model binding. Let’s work through a sample.

    Imagine you have a Recipe class that can hold all the information you need to make Love Mussels, and now you've decided to build a model binder to bind and validate recipes. 

    Iteration 1

    Let’s start with the naive approach. This code has a number of problems.

    public class RecipeModelBinder : IModelBinder
    {
        public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
            var form = controllerContext.HttpContext.Request.Form;
    
            var recipe = new Recipe();            
            recipe.Name = form["Name"];
            // ... and so on for all properties
    
            if (String.IsNullOrEmpty(recipe.Name))
            {
                bindingContext.ModelState.AddModelError("Name", "...");
            }
    
            return recipe;
        }
    }
    

    Problem

    The code works directly off the HttpContext.Request.Form.

    There are a couple difficulties working with the Form collection directly. One problem is how your tests will require more setup to create an HttpContext, Request, and Form objects.

    The second problem is related to culture. Values you need from the Form collection are culture sensitive because the user will type a date and time value into their browser using a local convention. However, the URL is another place you might need to check when binding values (the query string and routing data in general), and these values are culture invariant.

    Instead of worrying about all these details, it’s better to use the ValueProvider given to us by the incoming binding context. The value provider is easy to populate in a unit test, and takes care of culture sensitive conversions.

    Iteration 2

    We’ll add a GetValue method to help fetch values from the ValueProvider. At runtime the MVC framework populates the provider with values it finds in the request’s form, route, and query string collections.

    public class RecipeModelBinder : IModelBinder
    {
        public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
            var recipe = new Recipe();
            recipe.Name = GetValue<string>(bindingContext, "Name");
            // ... and so on for all properties
    
            if (String.IsNullOrEmpty(recipe.Name))
            {
                bindingContext.ModelState.AddModelError("Name", "...");
            }
    
            return recipe;
        }
    
        private T GetValue<T>(ModelBindingContext bindingContext, string key) 
        {
            ValueProviderResult valueResult;
            bindingContext.ValueProvider.TryGetValue(key, out valueResult);            
            return (T)valueResult.ConvertTo(typeof(T));
        }  
    }
    

    Problem:

    If you use any HTML Helpers (like Html.TextBox), you’ll see null reference exceptions when validation errors are present.

    One of the side-effects of model binding is that binding the model should put model values into ModelState. When an HTML helper sees there is a ModelState error for “Name”, it assumes it will also find the “attempted value” that the user entered. The helper uses attempted values to repopulate inputs and allow the user to fix any errors.

    Iteration 3

    The only change is to set the model value inside GetValue.

    private T GetValue<T>(ModelBindingContext bindingContext, string key)
    {
        ValueProviderResult valueResult;
        bindingContext.ValueProvider.TryGetValue(key, out valueResult);
        bindingContext.ModelState.SetModelValue(key, valueResult);       
        return (T)valueResult.ConvertTo(typeof(T));
    }  
    

    Problem:

    The model binder we’ve written so far will work with controller actions like the following:

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Create(Recipe newRecipe)
    {
        // ...
        return View(newRecipe);
    }
    

    But it won’t work in this scenario:

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Create(FormCollection formCollection)
    {
        var recipe = RecipeFactory.Create();
        TryUpdateModel(recipe);
        if (ModelState.IsValid)
        {
            // save it ...
        }
        return View(recipe);
    }

    The recipe in the controller action will never see any changes when calling TryUpdateModel, because the model binder is creating and binding data into its own recipe object. Perhaps you never use UpdateModel or TryUpdateModel, but if you expect your model binder to work in any possible situation, you need to make sure the model binder works when someone else creates the model.

    Iteration 4

    The only change is to check bindingContext.Model to see if we already have a model. Only when this property is null will we go to the trouble of creating a new model. 

    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var form = controllerContext.HttpContext.Request.Form;
    
        var recipe = (Recipe)(bindingContext.Model ?? new Recipe());
        recipe.Name = GetValue<string>(bindingContext, "Name");
        
        // ... 
    
        return recipe;
    }
    

    Problem:

    Congratulations! We just re-implemented the behavior of the DefaultModelBinder - only our model binder is stupid and only works with Recipes.

    If all we need is validation for a specific type of model, we can derive from the built-in binder and override OnModelUpdated or OnPropertyValidating and provide our custom logic.

    Iteration 5

    OnModelUpdated is easy to work with, so what follows is the entire listing for our custom model binder.

    public class RecipeModelBinder : DefaultModelBinder 
    {
        protected override void OnModelUpdated(ControllerContext controllerContext,
                                               ModelBindingContext bindingContext)
        {
            var recipe = bindingContext.Model as Recipe;
            if (String.IsNullOrEmpty(recipe.Name))
            {
                bindingContext.ModelState.AddModelError("Name", "...");
            }
        }
    }
    

    It turns out we didn’t need any code from those first four iterations, but I hope you find them useful because they demonstrate some common problems I’m seeing in custom model binders. Of course we could take this example even further and eliminate the magic strings, but we’ll leave the work for another day.

    In software development – every iteration is a learning opportunity!

This Blog

Syndication

Powered by Community Server, by Telligent Systems
'