Tuesday 25 October 2011

Using View Model with AutoMapper in MVC

Tools used when writing this post: MVC3, MvcScaffolding 1.0.0, EntityFramework 4.1.10331.0 and AutoMapper 2.0.0.

In this post, we will see a simple example of how to map a view model to a model class with AutoMapper. To understand more about view model, you may want to read http://rachelappel.com/use-viewmodels-to-manage-data-amp-organize-code-in-asp.net-mvc-applications. For more information about AutoMapper, see "AutoMapper - Getting Started".

Say we have a model class called Arena that is used by a database context class for Entity Framework. Then we have a view model for this class called ArenaViewModel that is created to handle slightly different form validation requirements from the original model class. Below are the model class and its view model:
public class Arena
{
    public int ArenaId { get; set; }
        
    [StringLength(150)]
    public string Name { get; set; }

    [StringLength(350)]
    public string Location { get; set; }
        
    public int NumberOfSeats { get; set; }
}

public class ArenaViewModel
{
    public int ArenaId { get; set; }

    //input requirement: field is required and can only have maximum 10 characters length 
    [Required]
    [StringLength(10)]
    public string Name { get; set; }

    //input requirement: field is required and can only have maximum 10 characters length
    [Required]
    [StringLength(10)]
    public string Location { get; set; }
                
    //input requirement: allow empty value (as this will be translated to 0 when saving to database)
    public int? NumberOfSeats { get; set; }
}

Then to set up AutoMapper, first copy and paste the class below to our project. Specify the mapping profile with a correct profile class name that we are going to create (line 6).
public class AutoMapperConfiguration
{
    public static void Configure()
    {
        // specify the mapping profile
        Mapper.Initialize(x => x.AddProfile<ViewModelProfile>());

        // Put this in unit testing later!
        // verify mappings
        Mapper.AssertConfigurationIsValid();
    }
}

Next, create the profile class. A profile class is used to centralized many mapping configurations in one place. A different profile can have different mapping configurations and formatting rules of similar entities in the other profile.
public class ViewModelProfile : Profile
{
    public override string ProfileName
    {
        get { return "ViewModel"; }
    }

    protected override void Configure()
    {
        // specify all mapping configurations here

        CreateMap<ArenaViewModel, Arena>();
    }
}
Note that this class is derived from Profile base class.

Then call
AutoMapperConfiguration.Configure();
from Application_Start() method on Global.asax.cs.

Say we already have a view called AddArenaInfo.cshtml that uses ArenaViewModel to add a new arena information:
@model MvcScaffoldTest.ViewModels.ArenaViewModel
@using (Html.BeginForm())
{
    @Html.ValidationSummary(true)
    <div class="editor-label">
        @Html.LabelFor(model => model.Name)
    </div>
    <div class="editor-field">
        @Html.EditorFor(model => model.Name)
        @Html.ValidationMessageFor(model => model.Name)
    </div>

    <div class="editor-label">
        @Html.LabelFor(model => model.Location)
    </div>
    <div class="editor-field">
        @Html.EditorFor(model => model.Location)
        @Html.ValidationMessageFor(model => model.Location)
    </div>

    <div class="editor-label">
        @Html.LabelFor(model => model.NumberOfSeats)
    </div>
    <div class="editor-field">
        @Html.EditorFor(model => model.NumberOfSeats)
        @Html.ValidationMessageFor(model => model.NumberOfSeats)
    </div>

    <p>
        <input type="submit" value="Create" />
    </p>
}

Then we would be able to do this on our controller:
[HttpPost]
public ActionResult AddArenaInfo(ArenaViewModel arenaVwMdl)
{
    if (ModelState.IsValid)
    {
        //map source to destination
        var arenaMdl = Mapper.Map<ArenaViewModel, Arena>(arenaVwMdl);
        context.Arenas.Add(arenaMdl);
        context.SaveChanges();
        return RedirectToAction("Index");
    }

    return View(arenaVwMdl);
}
AutoMapper will map those two objects automatically. We don't need to specify extra mapping configurations in this case because both of the classes have similar properties that can be easily matched by AutoMapper.

References:
http://mhinze.com/2009/07/06/automapper-in-nerddinner/
http://elegantcode.com/2009/10/06/automapper-introduction-and-samples-from-netdug/

Friday 21 October 2011

A VBScript Example to Copy Files to User Temp Folder

Below is an example of VBScript codes to copy files from current folder to '[User Profile]\Local Settings\Temp' folder then execute an executable file under the folder:
Set objShell = WScript.CreateObject("WScript.Shell")
currentFolder = objShell.CurrentDirectory

Dim filesys
Set filesys = CreateObject("Scripting.FileSystemObject")

Set appShell = CreateObject("Shell.Application")


'Set the destination folder to be checked/created

'these commented codes would use a folder under 'Program Files'
'Const PROGRAM_FILES = &H26&
'Set objFolder = appShell.Namespace(PROGRAM_FILES)
'Set objFolderItem = objFolder.Self
'Wscript.Echo objFolderItem.Path    'testing
'destinationFolderPath = objFolderItem.Path & "\MyApp\Install" 

'using '[User Profile]\Local Settings\Temp' folder, this value can be retrieved by using
'   filesys.GetSpecialFolder(2)     or      objShell.ExpandEnvironmentStrings("%temp%")
'testing - Wscript.Echo filesys.GetSpecialFolder(2)   ' or objShell.ExpandEnvironmentStrings("%temp%")
destinationFolderPath = objShell.ExpandEnvironmentStrings("%temp%") & "\MyApp.TMP"


'Check if folder exists
Dim newfolder
If Not filesys.FolderExists(destinationFolderPath) Then
    'if not then create one
    Set newfolder = filesys.CreateFolder(destinationFolderPath)
Else
    'clear all existing files under the destination folder
    filesys.DeleteFile(destinationFolderPath & "\*"), true  ' true - delete read only files
End If


'Copy all files under current folder to the destination folder
filesys.CopyFile currentFolder & "\*.*", destinationFolderPath & "\", true  ' true - overwrite existing


'Run installer
objShell.Run ("""" & destinationFolderPath & "\setup.exe" & """")
'objShell.Run ("""" & destinationFolderPath & "\setup.exe" & """"), 0, true     ' 0 - Hides the window and activates another window.
                                                                                ' true - the script should wait for the program to finish executing before continuing to the next statement


'Finalise
set appShell = Nothing
set filesys = Nothing
set objShell = Nothing
Wscript.Quit

Some Notes about Windows Installer, IExpress and VBScript


Choosing a deployment strategy for Visual Studio 2010
http://msdn.microsoft.com/en-us/library/e2444w33%28VS.100%29.aspx


ClickOnce
ClickOnce is a deployment technology that enables you to create self-updating Windows-based applications that can be installed and run with minimal user interaction. ClickOnce deployment overcomes three major issues in deployment:

- Difficulties in updating applications. With Microsoft Windows Installer deployment, whenever an application is updated, the user must reinstall the whole application; with ClickOnce deployment, you can provide updates automatically. Only those parts of the application that have changed are downloaded, and then the full, updated application is reinstalled from a new side-by-side folder.

- Impact to the user's computer. With Windows Installer deployment, applications often rely on shared components, with the potential for versioning conflicts; with ClickOnce deployment, each application is self-contained and cannot interfere with other applications.

- Security permissions. Windows Installer deployment requires administrative permissions and allows only limited user installation; ClickOnce deployment enables non-administrative users to install and grants only those Code Access Security permissions necessary for the application.
[http://msdn.microsoft.com/en-us/library/142dbbz4.aspx]


Walkthrough of creating an installer using Windows Setup Project
http://www.codeproject.com/KB/dotnet/Win_App_Setup_Project.aspx


Product Code and Package Code
If the new MSI file has the same ProductCode and PackageCode as a product that’s already installed, Windows indicates that you must repair or remove the product.

If the new MSI file has the same ProductCode as an installed product but a different PackageCode, you’ll receive a message indicating that another version of the product is already installed.

Repair does not use your new MSI file to repair the product, nor does it update what you previously installed. Instead, it repairs the existing installed product. That is, it behaves as if you went to the original MSI file used to install the existing product, selected the context menu, and chose repair. (Note: Repair can also be initiated from Add/Remove programs.)
[http://www.simple-talk.com/dotnet/visual-studio/updates-to-setup-projects/]


Creating bootstrapper packages
http://msdn.microsoft.com/en-us/library/ms165429.aspx


The difference between MSI and EXE file
http://www.symantec.com/connect/articles/understanding-difference-between-exe-and-msi


DISABLEADVTSHORTCUTS property of Setup.EXE
Setting the DISABLEADVTSHORTCUTS property disables the generation of shortcuts supporting installation-on-demand and advertisement. Setting this property specifies that these shortcuts should instead be replaced by regular shortcuts.
http://msdn.microsoft.com/en-us/library/windows/desktop/aa368297%28v=vs.85%29.aspx


Installation-on-demand and advertisement
With traditional installation technology, it is necessary to exit an application and rerun setup to perform an installation task. This commonly occurred when a user wanted a feature or product not chosen during the first run of setup. This often made the process of product configuration inefficient because it required the user to anticipate the functionality required before they ever used the product.

Installation-on-demand makes it possible to offer functionality to users and applications in the absence of the files themselves. This notion is known as advertisement. The Windows Installer has the capability of advertising functionality and to make installation-on-demand of application features or entire products possible. When a user or application activates an advertised feature or product, the installer proceeds with installation of the needed components. This shortens the configuration process because additional functionality can be accessed without having to exit and rerun another setup procedure.
[http://msdn.microsoft.com/en-us/library/windows/desktop/aa369293%28v=vs.85%29.aspx]


IExpress – How to use
http://home.wanadoo.nl/kixtart/download/IExpress.pdf

When IExpress extracts the files to a temporary directory and runs an installation command it watches the command it ran. When this process is finished, IExpress removes its temporary files from the drive.
[http://www.picturestoexe.com/forums/index.php?/topic/1983-maybe-you-didnt-know/]
http://www.mdgx.com/INF_web/iexpress.htm


SED file for IExpress - Overview
http://www.mdgx.com/INF_web/cdfinfo.htm


Running VBScript file from IExpress
http://markalexanderbain.suite101.com/distributing-a-vbscript-application-a90365


How to install shortcuts using VBScript:
http://ss64.com/nt/shortcut.html
http://www.vbforums.com/showthread.php?t=234891
http://www.appdeploy.com/messageboards/tm.asp?m=26758&mpage=1&key=梆

How to install application using VBScript:
http://www.symantec.com/connect/blogs/installing-application-using-vbscript
http://www.symantec.com/connect/downloads/vbscript-install-application-exit-code
http://msdn.microsoft.com/en-us/library/d5fk67ky%28v=vs.85%29.aspx
http://technet.microsoft.com/en-us/library/ee692649.aspx

VBScript examples for file management:
http://activexperts.com/activmonitor/windowsmanagement/adminscripts/filesfolders/files/
http://technet.microsoft.com/en-us/library/ee176983.aspx
http://www.computerperformance.co.uk/ezine/ezine139.htm

VBScript examples for special folders
http://www.activexperts.com/activmonitor/windowsmanagement/scripts/desktop/specialfolders/

Tuesday 18 October 2011

Dependency Injection for Filters with Ninject in MVC3 - Backward Compatibility

Tools used when writing this article: MvcScaffolding ver 1.0.0, Ninject ver 2.2.1.4 and Ninject.MVC3 ver 2.2.2.0.

This post will describe the third way to implement dependency injection for filters in MVC3.

For the preferred way to implement filter on actions or controllers using 'BindFilter' method, please see my previous post. The second way is also described on my other post.

In this post, we will see how to implement DI using 'Inject' attribute. This way of implementing is only meant for backward compatibility for MVC prior to version 3. For more information you can see https://github.com/ninject/ninject.web.mvc/wiki/Dependency-injection-for-filters and https://github.com/ninject/ninject.web.mvc/wiki/Injection-of-filter-attributes.

Setting up the DI for filter using this way is simpler, however we could not have a centralized location to specify where the filter applies. The reason is that we need to put the filter attribute on every controller(s) or action(s) where we want the filter to apply. So, if the filter is applied on lots of controllers or actions they could be harder to track.

First we prepare our filter class with a public service property that will be dependency injected. This property access modifier must be 'public', otherwise the DI will not work because the DI is going to be done through property injection. Then put '[Inject]' attribute notation on the property. When this notation is used, Ninject will automatically apply the injection to the property. Next, bind the service interface with its implementation class inside 'RegisterServices' method on 'NinjectMVC3.cs' file. Finally we can put the '[filterattribute]' notation on controller(s) or action(s) where we want the filter to apply.

Below are the complete codes:

Service interface and its implementation class:
public interface IGreetingService
{
    string GetGreeting();
}

public class GreetingServiceImplThree : IGreetingService
{
    public string GetGreeting()
    {
        return "Greeting - Backward Compatibility";
    }
}

Filter class:
public class GreetingFilterBackwardCompAttribute: ActionFilterAttribute
{
    [Inject]
    public IGreetingService _service { get; set; }

    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        ViewResult result = filterContext.Result as ViewResult;
        if (result != null)
        {
            result.ViewData["Greeting"] += _service.GetGreeting();
        }
    }
}

'RegisterServices' method on 'NinjectMVC3.cs':
private static void RegisterServices(IKernel kernel)
{
    . . .
    //bind the service interface with an implementation class
    kernel.Bind<IGreetingService>().To<GreetingServiceImplThree>();
    . . .
}   
Note here we just need to bind the service interface only, not the filter.

Usage:
[GreetingFilterBackwardComp]
public ViewResult Index()
{
    . . .
} 
To test, render 'ViewData["Greeting"]' somewhere on the view or shared view.

Monday 10 October 2011

Dependency Injection for Filters with Ninject in MVC3 - Using Filter Attribute

Tools used when writing this article: MvcScaffolding ver 1.0.0, Ninject ver 2.2.1.4 and Ninject.MVC3 ver 2.2.2.0.

This post will describe the second way to implement dependency injection for filters in MVC3.

For the preferred way to implement filter on actions or controllers using 'BindFilter' method, please see my previous post.

In this post, we will see that we can also implement dependency injection with Filter Attributes. The steps to do this are almost similar to the steps to implement using the 'BindFilter' method (described on my previous post referred above). Except now a new attribute class that derived from 'FilterAttribute' needs to be created. Then we need to modify our filter binding in the 'RegisterServices' method to use extension methods such as 'WhenActionHas', 'WhenControllerHas' or 'WhenActionMethodHas' to refer to the attribute class. After that, the filter can be applied to a specific action or controller by putting '[filterattribute]' notation. We'll see this in more details below.

Based on our previous example, we need to add an attribute class that derived from 'FilterAttribute' base class. Nothing change on the main filter class (ie. GreetingFilter class). Below is the code for the attribute class:
public class GreetingFilterAttribute : FilterAttribute { }
Note that it is just an empty class without implementation.

Next, in our 'RegisterServices' method, we need to bind the filter attribute using extension methods such as 'WhenActionHas', 'WhenControllerHas' or 'WhenActionMethodHas'. For example:
kernel.BindFilter<GreetingFilter>(FilterScope.Action, 0)
.WhenActionMethodHas<GreetingFilterAttribute>();
The main difference in implementing DI this way compared to the first way that is described on my previous post is that inside this 'RegisterServices' method, we just need to tell the kernel to look for a filter attribute. The details of the location(s) where the filter applies is specified using '[filterattribute]' notation (on some controllers or actions). While on the first way, the specific location(s) where the filter applies is specified in the binding as well.

Then lastly, we put '[GreetingFilter]' notation on particular action(s) or controller(s) where we want the filter to apply.

Below are the complete codes:

Service interface and its implementation class:
public interface IGreetingService
{
    string GetGreeting();
}

public class GreetingServiceImplTwo : IGreetingService
{
    public string GetGreeting()
    {
        return "Greeting - Using Filter Attribute";
    }
}

GreetingFilter and it's attribute class:
public class GreetingFilter : IActionFilter
{
    private readonly IGreetingService _service;

    public GreetingFilter(IGreetingService greetingService)
    {
        this._service = greetingService;
    }

    public void OnActionExecuting(ActionExecutingContext filterContext)
    {
        //at the moment this is empty because we don't need this method
    }

    public void OnActionExecuted(ActionExecutedContext filterContext)
    {
        ViewResult result = filterContext.Result as ViewResult;
        if (result != null)
        {
            result.ViewData["Greeting"] += _service.GetGreeting();
        }
    }
}

public class GreetingFilterAttribute : FilterAttribute { }

'RegisterServices' method on 'NinjectMVC3.cs':
private static void RegisterServices(IKernel kernel)
{
    . . .
    //bind the service interface with an implementation class
    kernel.Bind<IGreetingService>().To<GreetingServiceImplTwo>();

    //bind the filter attribute
    kernel.BindFilter<GreetingFilter>(FilterScope.Action, 0)
        .WhenActionMethodHas<GreetingFilterAttribute>();
    . . .
}   

Usage:
[GreetingFilter]
public ActionResult Create()
{
    . . .
} 
To test, render 'ViewData["Greeting"]' somewhere on the view or shared view.

Sunday 2 October 2011

Dependency Injection for Filters with Ninject in MVC3

Tools used when writing this article: MvcScaffolding ver 1.0.0, Ninject ver 2.2.1.4 and Ninject.MVC3 ver 2.2.2.0.

There are three ways (as far as I know) to do dependency injection for filters in MVC3 using Ninject.

On this post, we'll see the preferred way first. The second way which uses filter attribute is described on my next post. While the third one which should only be used for backward compatibility can be seen on my other post.

First, we create a filter class that inherits from one of these four interfaces; IAuthorizationFilter, IActionFilter, IResultFilter or IExceptionFilter. Each interface requires us to implement particular methods defined for it. For example when we use IActionFilter, we need to implement OnActionExecuting and OnActionExecuted methods. For more information about this, see this MSDN article "Filtering in ASP.NET MVC".

Then bind the filter in the 'RegisterService' method inside 'NinjectMVC3.cs' file using 'BindFilter' method. Here we specify where the filter will apply (which controller or action or a combination of both). I'm assuming that you have used NuGet to implement Ninject in your project. That way, you will have 'NinjectMVC3.cs' file generated for you.

If you haven't implemented Ninject on your project, you can see my post "Building MVC Application using Dependency Injection with MVCScaffolding and Ninject" on how to install it.

Let's go through an example. In this example, we are going to implement a simple action filter that returns a greeting message through ViewData.
First, we create a simple service interface and an implementation class.
public interface IGreetingService
{
    string GetGreeting();
}

public class GreetingServiceImplOne : IGreetingService
{
    public string GetGreeting()
    {
        return "Greeting..";
    }
}

Then we create our filter class. Because it is an action filter, it will use IActionFilter to be inherited from.
public class GreetingFilter : IActionFilter
{
    private readonly IGreetingService _service;

    public GreetingFilter(IGreetingService greetingService)
    {
        this._service = greetingService;
    }

    public void OnActionExecuting(ActionExecutingContext filterContext)
    {
        //at the moment this is empty because we don't need this method
    }

    public void OnActionExecuted(ActionExecutedContext filterContext)
    {
        ViewResult result = filterContext.Result as ViewResult;
        if (result != null)
        {
            result.ViewData["Greeting"] += _service.GetGreeting();
        }
    }
}
Notice the class includes a private service member and a constructor to inject a service object to itself.

Lastly, we need to bind the filter inside 'RegisterServices' method in 'NinjectMVC3.cs' class. In this case we state that the filter would only apply to the Index action of PlayersController.
private static void RegisterServices(IKernel kernel)
{
    kernel.Bind<IGreetingService>().To<GreetingServiceImplOne>();

    //filter is applied to Index action of PlayersController
    kernel.BindFilter<GreetingFilter>(FilterScope.Action, 0)
        .When((controllerContext, actionDescriptor) =>
            actionDescriptor.ControllerDescriptor.ControllerType == typeof(PlayersController) &&
            actionDescriptor.ActionName == "Index");
            
    //this one here is similar as the one above            
    /*kernel.BindFilter<GreetingFilter>(FilterScope.Action, 0)
        .When((controllerContext, actionDescriptor) => 
            actionDescriptor.ControllerDescriptor.ControllerName == "Players" &&
            actionDescriptor.ActionName == "Index");*/

    //this is another example where the filter to be applied to all actions of MatchesController
    //kernel.BindFilter<GreetingFilter>(FilterScope.Action, 0).WhenControllerType<MatchesController>();
}        
Notice that, first we bind the service interface with its implementation class. Then we configure the filter using 'BindFilter' method to particular controller(s) or action(s). The commented codes show some more configuration examples.

To see more possible filter configuration see these official Ninject MVC documentation for filters; https://github.com/ninject/ninject.web.mvc/wiki/Filter-configurations and https://github.com/ninject/ninject.web.mvc/wiki/Conditional-bindings-for-filters

To test our work, just try to render our ViewData on some view pages. In my case I use a shared page for all of my views which is '_Layout.cshtml' (under 'Views/Shared' folder), so I just need to render the ViewData there and test the result.

Easy..