2012-12-12

Web Api: Passing a Complex type in JSON

,

In one project i wanted to pass a complex type to the Post method of an Web Api controller. The Post itself will be done using JQuery in the JSON format. I noticed that the parameter was always null. After a bit of searching i found the solution.

The Set Up

Server side

public class ValuesController : ApiController
{
// POST api/values
public void Post(MyComplexType value)
{
}
}

public class MyComplexType
{
public string Name { get; set; }

public MyComplexSubType MyComplexSubType { get; set; }
}

public class MyComplexSubType
{
public int Age { get; set; }
}

Client Side

 <script type="text/javascript">

function
MyComplexSubType()
{
var self = this;

self.Age = 26;
}

function MyComplexType()
{
var self = this;

self.Name =
"Kenny Tordeur";
self.MyComplexSubType =
new MyComplexSubType();
}


function PostComplexType()
{
$.ajax(
"/api/values", {
data: JSON.stringify(
new MyComplexType()),
contentType:
'application/json',
type:
'POST',
success: SendComplexTypeCallBack
});
}


function SendComplexTypeCallBack(data)
{
alert(
"Complex type sended");
}
</script>

The PostComplexType will be trigged by a click event on a button. It will create a javascript object called MyComplexType. This object will map directly to the object we created on the server side.


 


image


The missing link


With this set-up the parameter will always be null. We need to add a line of code to the global.asax.

ValueProviderFactories.Factories.Add(new JsonValueProviderFactory());

 


Value providers are used by the model binding system in MVC to populate the values of model objects. We basically add a provider that enables to bind a model to a JSON model.  The solution can be downloaded here.

Read more →

2012-12-07

WebApi: File upload and download using JQuery and submit button

,

I am going to create a WebApi service called FileService that can be used to upload and download files. The service will only contain 2 methods. A Post to upload and a Get method that accepts an id parameter to identify the file that needs to be downloaded. Let’s start with the Post method.

The Post method

This method will look in the Request object to see if there are any posted files. If so, it will loop over the files and create them on the server side. The server will return a 201 HttpStatus and a list of strings that will contain the full path of the file(s) at server side. When there are no files posted, the service will return a 401 status a.k.a. BadRequest.

public HttpResponseMessage Post()
{
HttpResponseMessage result = null;
var httpRequest = HttpContext.Current.Request;

// Check if files are available
if (httpRequest.Files.Count > 0)
{
var files = new List<string>();

// interate the files and save on the server
foreach (string file in httpRequest.Files)
{
var postedFile = httpRequest.Files[file];
var filePath = HttpContext.Current.Server.MapPath("~/" + postedFile.FileName);
postedFile.SaveAs( filePath);

files.Add(filePath);
}

// return result
result = Request.CreateResponse(HttpStatusCode.Created, files);
}
else
{
// return BadRequest (no file(s) available)
result = Request.CreateResponse(HttpStatusCode.BadRequest);
}

return result;
}

The Get Method


As mentioned before, the Get Method will accept a string file that will identify (= filename) the file that needs to be downloaded.

public HttpResponseMessage Get(string id)
{
HttpResponseMessage result = null;
var localFilePath = HttpContext.Current.Server.MapPath("~/" + id);

// check if parameter is valid
if (String.IsNullOrEmpty(id))
{
result = Request.CreateResponse(HttpStatusCode.BadRequest);
}
// check if file exists on the server
else if (!File.Exists(localFilePath))
{
result = Request.CreateResponse(HttpStatusCode.Gone);
}
else
{// serve the file to the client
result = Request.CreateResponse( HttpStatusCode.OK);
result.Content = new StreamContent(new FileStream(localFilePath, FileMode.Open, FileAccess.Read));
result.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
result.Content.Headers.ContentDisposition.FileName = id;
}

return result;
}

Uploading a File


Using a submit  button

 <form name="form1" method="post" action="api/file" enctype="multipart/form-data">
<
div>
<
label>
Using submit</label>
<
input name="myFile" type="file" />
</
div>
<
div>
<
input type="submit" value="Submit" />
</
div>
</
form>


Using JQuery

<form enctype="multipart/form-data">
<
label>
Using JQuery</label>
<
input name="file" type="file" />
<
input type="button" id="Upload" value="Upload" />
</
form>
        <script type="text/javascript">
$(function () {
$('#Upload').click(function () {
var formData = new FormData($('form')[0]);
$.ajax({
url: 'api/file',
type: 'POST',
// Form data
data: formData,
//Options to tell JQuery not to process data or worry about content-type
cache: false,
contentType: false,
processData: false
});
});
});
</script>

Downloading a File


image


Summary


The solution can be downloaded here.

Read more →

2012-12-01

Paged Grid with Knockout.js and WebApi

,
I want to see how easily you can create a custom grid that uses an WebApi as datasource and that allows the user to page the data and also allow them to choose a page size for the grid.

The WebApi

The WebApi will return a viewmodel that contains an array of names (string) and a property that specifies how many pages that there are available.
    public class NamesGridViewModel
    {
        public IEnumerable<String> Names { get; set; }

        public int NumberOfPages { get; set; }
    }

The WebApi itself will contain a method that accepts 2 parameters. The parameters will be page (the page that we request) and pagesize (how many entries a page contains). This method will be responsible for calculating how many pages there are and to serve the requested names based on the 2 parametes.
    public class ValuesController : ApiController
    {
        public IList<String> Names
        {
            get { return new List<String> { "Fred", "Barney", "Betty", "Wilma", "Bart", "Lisa", "Maggie", "Homer", "Marge" }; }
        }
            
        public NamesGridViewModel Get(int page, int pagesize)
        {
            return new NamesGridViewModel
                       {
                           // get the request names for the specific page
                           Names = (0 == page? null : Names.Skip((page - 1)*pagesize).Take(pagesize).ToArray())
                           ,
                           // calculated number of pages and ceil the value
                           NumberOfPages = ((int) Math.Ceiling((double) Names.Count/pagesize))
                       };
        }
    }

The client


The client will need a reference to kockout.js. With knockout.js it is possible to apply the MVVM pattern and also work with templates in javascript.


The UI

Page size: <select data-bind="options: availablePageSize, optionsText: $data, value: selectedPageSize"></select><!-- the grid --><table data-bind="with: namesGridViewModel">
    <thead>
        <tr>
            <th>
                Name
            </th>
        </tr>
    </thead>
    <tbody data-bind="foreach: Names">
        <tr>
            <td data-bind="text: $data">
            </td>
        </tr>
    </tbody>
</table><!--Contains the page links--><div id="pager"></div>

The Javascript

<script type="text/javascript">
    // Our  ViewModel.
    function pageViewModel() {
        var self = this;
        self.namesGridViewModel = ko.observable(); // contains the viewmodel returned by the WebApi
        self.selectedPageSize = ko.observable(3); // contains the selected page size, default value is 3
        self.availablePageSize = ko.observableArray([1, 2, 3, 4, 5]); // contains the available page sizes a user can select
        self.selectedPage = ko.observable(1); // contains the selected page

        // Add a click event to all future element with a class "pageIndex". This event will fire
        // when the user clicks a specific page.
        $("#pager").on("click", ".pageIndex", function (event) {
            // set the selected page in the viewModel
            self.selectedPage($(this).text());
        });

        // This function will be used to get the data from our WebApi. The requested page and page size are passed
        // as a parameter. The result will be stored in the namesGridViewModel property. This will cause that the subscribe event
        // for the namesGridViewModel will be fired ==> the page links will be created.
        self.navigate = function () {
            $.get("/api/values?page=" + self.selectedPage() + "&pagesize=" + self.selectedPageSize(), self.namesGridViewModel);
        };

        // Function that will subscribe to all the needed events.
        self.SubscribeToEvents = function () {

            // This event will fire when selectedPageSize is changed.
            self.selectedPageSize.subscribe(function (newValue) {
                self.selectedPage(1);
                self.navigate();
            });

            // This event will be fired when the selectedPage is changed.
            self.selectedPage.subscribe(function (newValue) {
                self.navigate();
            });

            // This event will fire when a new value is defined for the namesGridViewModel.
            // It will create the page links below the grid.
            self.namesGridViewModel.subscribe(function (newValue) {
                var numberOfPages = newValue.NumberOfPages;
                var $pager = $("#pager");
                // clear the pager
                $pager.html("");
                // created the pages the user can click on
                for (var i = 1; i <= numberOfPages; i++) {
                    var link = $('<a class="pageIndex">' + i + '</a>');
                    $pager.append(link);
                }
            }, this);
        };
        
        // This function will be used to kick start everything.
        self.bind = function () {
            self.SubscribeToEvents();
            self.navigate();
            ko.applyBindings(self);
        }
    }
    // Create the viewModel and bind it.
    $(function () { new pageViewModel().bind(); })</script>

The result


image

Summary


You have seen how to create a basic paging grid using Knockout.js.You can easily extend this example to also allow sorting. The solution can be downloaded here.
Read more →

2012-11-28

Nuget package: integrated MEF in Asp.Net MVC 4 and WebApi

,
Today i wanted to create my first Nuget package and i already knew what i would publish to the world. I wanted to make the code that is used to use MEF in Asp.Net MVC 4 and the WebApi (view this post) easy to reuse in other projects. I rewrote the code in a class libary.
After a little google-ing i found a video that explained how to create a Nuget package using the Nuget Package Explorer.  After that i created a user at the Nuget gallery so i got my API Key. With this, i had all the information i needed to published my first Nuget package and i have a feeling that it will not be my last :-)
The package can be installed from the Package Manager Console by typing: Install-Package MEF.MVC4
Read more →

2012-08-31

MEF in Asp.Net MVC 4 and WebApi

,
MEF stands for “Microsoft Extensibility Framework”. If you want an overview of MEF, you can look here. In this post we will integrated MEF with Asp.Net MVC 4 and with the WebApi.

Asp.Net MVC 4

First of all you need to reference the “System.ComponentModel.Composition.dll” assembly which contains the implementation of MEF. Now where are going to create a MEF controller factory. Like the name says, it will be responsible to create the controller that is requested.

public class MefControllerFactory : DefaultControllerFactory
   {
       private readonly CompositionContainer _compositionContainer;

       public MefControllerFactory(CompositionContainer compositionContainer)
       {
           _compositionContainer = compositionContainer;
       }

       protected override IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, Type controllerType)
       {
           var export = _compositionContainer.GetExports(controllerType, null, null).SingleOrDefault();

           IController result;

           if (null != export)
           {
               result = export.Value as IController;
           }
           else
           {
               result = base.GetControllerInstance(requestContext, controllerType);
               _compositionContainer.ComposeParts(result);
           }
         
           return result;
       }
   }

The MefcontrollerFactory will inherit from the DefaultControllerFactory and has a constructor that accepts a CompositionContainer. To plug in MEF, the GetControllerInstance methode will be overridden. First will look in our exports if something is defined for the requested controller type. Mark that the SingleOrDefault method is used because if more exports are defined for a controller, an exception will be throw. If this exception is thrown, something is wrong with the configuration of the CompositionContainer. If a single export is found, we’ll get the object from the Value property.


If the export isn’t found, the base method will be invoked. That way, the controller is created the default-way. When the controller is created, the ComposeParts method on the CompositionContainer is invoked. This will resolve the needed import for the controller.



This is the object that will be injected. The GetMessage method will return a string that will be shown on the view.
public interface IMyTest{
    String GetMessage();
}

[Export(typeof(IMyTest))]
public class MyTest1 : IMyTest{
    public MyTest1()
    {
        creationDate = DateTime.Now;
    }

    public string GetMessage()
    {
        return String.Format("MyTest1 created at {0}", creationDate.ToString("hh:mm:ss")) ;
    }

    private DateTime creationDate;
}


The Export attribute says to MEF that this class can be exported. The type of IMyTest is pasted as a parameter. This indicates the contract that is used. So when an IMyTest is requested from MEF, an object of MyTest1 is returned.
[Export]
public class HomeController : Controller{
    [Import]
    private IMyTest _myTest;

    public ActionResult Index()
    {
        ViewBag.Message = _myTest.GetMessage();

        return View();
    }
}

The HomeController is marked for export and an import attribute is put on the “_mytest” property. Of course we still need to configure MVC to use our MefControllerFactorty. To accomplish this, is created a static class with one static public method (RegisterMef). This method will create a Mef CompositionContainer and pass this container to the MefControllerFactory. This MefControllerFactory will be set as the controller factory for MVC. To configure the CompositionContainer an AssemblyCatalog is used.
public static class MefConfig{
    public static void RegisterMef()
    {
        var container = ConfigureContainer();

        ControllerBuilder.Current.SetControllerFactory(new MefControllerFactory(container));
        
        var dependencyResolver = System.Web.Http.GlobalConfiguration.Configuration.DependencyResolver;
    }

    private static CompositionContainer ConfigureContainer()
    {
        var assemblyCatalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
        var container = new CompositionContainer(assemblyCatalog);
        
        return container;
    }
}

The RegisterMef method will be called form the Application_Start method that resides in the global.asax.
public class MvcApplication : System.Web.HttpApplication{
     protected void Application_Start()
     {
        AreaRegistration.RegisterAllAreas();

        MefConfig.RegisterMef();

        WebApiConfig.Register(GlobalConfiguration.Configuration);
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);
        AuthConfig.RegisterAuth();
     }
}

When the Index action for the HomeController is requested through the browser, everything works just fine but when it is requested it again, an exception is thrown.

A single instance of controller 'MvcApplication5.Controllers.HomeController' cannot be used to handle multiple requests. If a custom controller factory is in use, make sure that it creates a new instance of the controller for each request.


This exception is thrown because the lifetime of the controller is linked to the lifetime of the CompositionContainer. The container keeps a reference to all the objects that it has created. If the same object is requested, the reference of the previous object is given. There are 2 ways to solve this problem.

You could pass an instance of a ComposablePartCatalog (in this case the AssemblyCatalog) to the MefControllerFactorty. Then in the “GetControllerInstance” method always compose a new CompositionContainer to resolve the controller. Personally I'm not really found about that.

The other solution is to use a CreatonPolicy. If we put a CreationPolicy of “NonShared” on the HomeController, a new instance of the HomeController is created from scratch every time it gets requested. Since this a standard feature of MEF, I'll use this solution.
[Export]
[PartCreationPolicy(CreationPolicy.NonShared)]
public class HomeController : Controller{
    [Import]
    private IMyTest _myTest;

    public ActionResult Index()
    {
        ViewBag.Message = _myTest.GetMessage();

        return View();
    }
}

Now we can request the controller as many times as we want.


WebApi


This is the created WebApi controller. Mark that the controller also has a CreationPolicy defined. This is for the same reason a mentioned above.
[Export]
[PartCreationPolicy(CreationPolicy.NonShared)]
public class HomeController : ApiController{
    [Import]
    private IMyTest _myTest;

    public String GetMessage()
    {
        return _myTest.GetMessage();
    }
}

To plug in MEF in the WebApi a object needs to be created from the System.Web.Http.Dependencies.IDependencyResolver interface. This is how the object looks like.
public class MefDependencyResolver : IDependencyResolver{
    private readonly CompositionContainer _container;
    
    public MefDependencyResolver(CompositionContainer container)
    {
        _container = container;
    }

    public IDependencyScope BeginScope()
    {
        return this;
    }

    public object GetService(Type serviceType)
    {
        var export = _container.GetExports(serviceType, null, null).SingleOrDefault();

        return null != export ? export.Value : null;
    }

    public IEnumerable<object> GetServices(Type serviceType)
    {
        var exports =_container.GetExports(serviceType, null, null);
        var createdObjects = new List<object>();

        if ( exports.Any())
        {
            foreach (var export in exports)
            {
                createdObjects.Add(export.Value);
            }
        }

        return createdObjects;
    }

    public void Dispose()
    {
        ;
    }
}



The “BeginScope” method returns a scope in with the create objects will life. Since we are going to use MEF to control the lifetime of the created objects, we can do a return of “this”.  We can do this because the IDependencyResolver inherits form IDependencyScope. If you really need a limited scope per request, the “BeginScope” method always needs to return a new object of type IDependencyScope.

You also need to implement a “Dispose” method to release the used resources. In the MefDependencyResolver, it isn’t implemented. This is because we return the current instance in the “BeginScope” method. If we disposed the CompositionContainer, we could only request the service once.


Right now, the only thing needed, is the register the create MefDependencyResolver. This will be done in the modified MefConfig class.
public static class MefConfig
   {
       public static void RegisterMef()
       {
           var container = ConfigureContainer();

           ControllerBuilder.Current.SetControllerFactory(new MefControllerFactory(container));
           
           var dependencyResolver = System.Web.Http.GlobalConfiguration.Configuration.DependencyResolver;
           System.Web.Http.GlobalConfiguration.Configuration.DependencyResolver = new MefDependencyResolver(container);
       }

       private static CompositionContainer ConfigureContainer()
       {
           var assemblyCatalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
           var container = new CompositionContainer(assemblyCatalog);
           
           return container;
       }
   }



The example can be downloaded from here.
Read more →

2012-08-14

Entity Framework: Database Migrations

,

If you don’t like writing SQL DDL statement, like me, than Entity Framework is very handy. With the Code-First, you can write your model and don’t need to worry about your database. It is generated for you by Entity Framework. This is very handy but what if you are working with an existing database? Or if you need to support different versions of your database? That is where database migrations come in to play.

Before we start

  1. Create an Asp.Net MVC 4 application
  2. Use Nuget to install the latest version of the Entity Framework (5.0.0-rc)

Because i am not running an SQL Express or SQL Server on my machine, i am also going to install SqlServerCompact so i can work with an SDF file. This needs a little more configuration.

  1. Install EntityFramework.SqlServerCompact form Nuget.
  2. Change the connectionstring in the web.config
      <connectionStrings>
        <
    add name="DefaultConnection" connectionString="Data Source=|DataDirectory|\DBTest.sdf;Max Database Size=2047" providerName="System.Data.SqlServerCe.4.0" />   
      </
    connectionStrings>

Create your models. In my case i will create as Car and Make class.

namespace EF_DatabaseMigrations.Models
{
public class Car
{
public Int32 Id { get; set; }

public String Model { get; set; }

public Make Make { get; set; }
}

public class Make
{
public Int32 Id { get; set; }

public String Name { get; set; }
}
}

Next i will create a DbDatasource that will map my entities to the database. This datasource will pass the name of the connectionstring to the base constructor.

namespace EF_DatabaseMigrations.DB
{
public class DbDatasource : DbContext
{
public DbDatasource()
: base("DefaultConnection")
{ }

public DbSet<Car> Cars { get; set; }

public DbSet<Make> Makes { get; set; }
}
}

Let’s migrate


To configure your application to use migrations, you have to type “enable-migrations” command in the Package Manager Console. This will create a Migrations folder that contains a Configuration file. This class contains a seed method that accepts the DbDatasource as a parameter. The seed method will always be execute when you update your database. This method will typically be used to create users in the database or in our case to create the Makes in our database.  By default, AutomaticMigrationsEnabled will be set to false. Since we want to automate everything, we need to set it to true :-).


namespace EF_DatabaseMigrations.Migrations
{
internal sealed class Configuration : DbMigrationsConfiguration<EF_DatabaseMigrations.DB.DbDatasource>
{
public Configuration()
{
AutomaticMigrationsEnabled = true;
}

protected override void Seed(EF_DatabaseMigrations.DB.DbDatasource context)
{
context.Makes.AddOrUpdate(m => m.Name, new Make { Name = "Ford" }
, new Make { Name = "Opel" }
, new Make { Name = "BMW" });
}
}
}

Because the Seed method is always called, we have to make sure that the Makes we are adding, only are getting inserted if they don’t exists or are updated when they do exists the database. That is why we are using the AddOrUpdate methode. The first parameter is in fact our condition for the insert or update. If a make with a name “Ford” doesn’t exists in the database, it is inserted. If it does exists, it gets updated.


 


When we type “update-database” command in the Package Manager Console, EF will create our database and will call the Seed method. The location of the database will be determined by the connectionstring that you specify. In our case it will be found in the App_Data folder.


When we open the database, we see that a Cars and a Makes table are created. The Makes table is pre-filled.


 image


In the table “_MigrationHistory” all migrations that where performed on this database are stored. That way you can always see what version of database this is. Also Entity Framework will need this information.


Now let’s assume that we want to add a BuildDate property to the Car. We can put this in a new migration. This way we can keep track of all our modifications in our database.


Change the Car entity.


    public class Car
    {
    public Int32 Id { get; set; }

    public String Model { get; set; }

    public Make Make { get; set; }

    public DateTime BuildDate { get; set; }
    }

Add Migration


Type “add-migration AddBuildDate” in the Package Manager Console. This will create a new file in the Migration folder. The file name will contain the date + the name that we specified.


This new file will contain 2 methods that we can override. The “Up” method will contain all new database modifications. The “Down” will contain the rollback of the modifications. This way we can easily “jump” through database versions. We manually add the AddColumn and DropColumn statements.

namespace EF_DatabaseMigrations.Migrations
{
public partial class AddBuildDate : DbMigration
{
public override void Up()
{
AddColumn("dbo.Cars", "BuildDate", c => c.DateTime(nullable: false));
}

public override void Down()
{
DropColumn("dbo.Cars", "BuildDate");
}
}
}

When we want to apply those modifications, we need to type “update-database -TargetMigration:AddBuildDate”. This will modify our database and add the new column.


image


 


If you want to rollback the database at it’s begin state, you type “update-database -TargetMigration:0” in the Package Console Manager.


What about the database adminstrators


We can’t forget these guys. They probably won’t like this way of creating the database and would probably prefer a script. Well you can add an extra parameter to the “update-database” called script that will create a clean SQL script that performs all the necessary steps to create the database.


“update-database –TargetMigration:AddBuildDate –script” will create this script:

ALTER TABLE [Cars] ADD [BuildDate] [datetime]
INSERT INTO [__MigrationHistory] ([MigrationId], [Model], [ProductVersion]) VALUES ('201208140904052_AddBuildDate', 0x1F8B0800000000000400ECBD07601C499625262F6DCA7B7F4AF54AD7E074A10880601324D8904010ECC188CDE692EC1D69472329AB2A81CA6556655D661640CCED9DBCF7DE7BEFBDF7DE7BEFBDF7BA3B9D4E27F7DFFF3F5C6664016CF6CE4ADAC99E2180AAC81F3F7E7C1F3F22FEC7BFF71F7CFC7BBC5B94E9655E3745B5FCECA3DDF1CE4769BE9C56B36279F1D947EBF67CFBE0A3DFE3E8374E1E9FCE16EFD29F34EDF6D08EDE5C369F7D346FDBD5A3BB779BE93C5F64CD78514CEBAAA9CEDBF1B45ADCCD66D5DDBD9D9D83BBBB3B777302F111C14AD3C7AFD6CBB658E4FC07FD79522DA7F9AA5D67E517D52C2F1BFD9CBE79CD50D317D9226F56D934FFECA3D367BFFFD3ACCD2659937F515CD4594B0835E3A74F3E4A8FCB22237C5EE7E5F97B22B7F310C87D64BBA58E4F09C1F6FACDF52AE7CE3FFBE824ABFD06D4E4F7CAAF830FE8A39775B5CAEBF6FA557EAEAF9DCD3E4AEF86EFDDEDBE685FF3DE41CFF4DBB2BDB7F751FA625D96D9A4A40FCEB3B2C93F4A579F3E7ADD5675FE79BECC8904F9EC65D6B679BDC4BB3963AE1478B4FAF47644787877670F44B89B2D9755CB54ED21DE4193E7CA60FABAAD89653E4A9F15EFF2D9F37C79D1CE2DB65F64EFCC27FB3B3BC4395F2D0B62317AABADD7B93F3CF97B73B74FD645392316C84DD7F8FD0D7153844E1D482FB2CBE282C7D61D4AF6965ABFCA4B61A779B1123E1AD3ACFFFEF2E5B3BA5ABCAA00DB7CF6FBBFAED6F51468549D2FDE64F545DE86DD3FBEEB586A23A371773FE2341F4DFCFBB3CD6843F373DC34D5B460349D26F8FD239374BA9CA5430C22982B43119EEBB22D566531A5FE3EFBE85BBDE147401996F240095F86B076C6E3DDEEB8BC11F4198F546F9B1534B73AB8A71368D74610EF6285175EE7ADA343F351EAA8E68FB037A0F055A01E7B5786D479D9C33FE85C05D3FBBA2BB45DA1D93045164333AE1089CD93E2BDAC23EB0A62388608DBD97970B6EFAE183F6324EF0E58C9C75F64AB1589846735F593F4B598CC93EDD7EF6F101702E3EEB489D8458BADED897444769177BEA5AE09D36745DDB4C6667F949ECC16BD66B7E13AD395C77CFD2932FC641AE3777961C86F607EED0072247C46A35A909EE301EAF00C93F4DF4AE1B064655647D4EC4955AE17CB2155BDE96DB5B33E00FDE8F6303CA3E9C3F13EEEC37A7CB743842EB93D8DA92D3B5CDF9DBB5BCDAC48D03732B53125708BB98DBFF6B333B962DAFCF7E5931FFE74842AAA276DAA6D6F4175D7F8164203B5DA214957BDF62971AB796010B1C900216C9FEF818E9A8AAF89CE7B6342EA7156B0DB71D6C071B15ECE2D06D93538FD09EFD99D6E13CB6ED6FE74ECCC63D5F98131626A7443B69E1190261FA534F4CB620603F0FABA69F3C5180DC6AF7F51F93AAF29263DC9C7FB08344DB32FB265719E37ED9BEA6D4EB69EBFFBBA419FF5429B6656FEBF30F22B96ADCACF26CFFBA6806753C4B6BCCCEAE99CDDD1AEDBFC8101D98C7E4778FFFEF8196EF668F0757CF6DE14FEDCC4543F2B7328E6E183A6F01B0C759C5178AFA02480C101C3FB86483447790D126625A9B0A6AD4989F52CE24B0A15A7C52A2B7D6CFBFAFB36F30EAA5970DD6F9EE6AB7C8909F546749B6E3698280BB2C37D378DFB3DC3BDBE7FDE9DA55ECC3714F2895227E99F54349DC27BB1502A1A0C0EC68231A8F118EB67234CF45173AEE10DB1613798FCD98906FBD6979863BDB4695562CAA6B87020E04F2CF369C016B6CDD9F2BC32ECD9C1C834E9AAEABCCD48CF67C7755B9C67D396BE9EE64DC3A9999FCCCA3535395D4CF2D9D9F2CB75BB5AB734E47C3129AF7D6280CB37F5CF216F88F3E32F57EC677E134320340B98AA2F976CC12CDECFFA6A780804C447753BE6B2858EBFB8B6905E54CB5B0252F23D3552FF265FAC281999375F2E5F6797F9306E37D330A4D8E3A74546CEFAA249EF1E09D3787C42EC4739FAA3FF270000FFFFEA4946EC18180000, '5.0.0-rc.net40')


The Visual Studio solution can be downloaded here.

Read more →

2012-05-16

ASP.NET MVC: Set Focus, ViewModel Style

,

In a recent Asp.Net MVC project i had to set a focus on a specific control, but it wasn’t just a specific control. It was calculate in runtime by some conditions. I didn’t just want to create an extra string property on the viewmodel where i could store the id of the control. Off course this would also work but i wanted something safer than those magic strings.

In one of my previous posts (Where is the ClientID?), i was able to determine the Id that is created by the HtmlHelper to create a textbox, checkbox, …

public static class HtmlHelper
{
public static String GetId<TModel,TProperty>( this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression )
{
return TagBuilder.CreateSanitizedId(ExpressionHelper.GetExpressionText(expression));
}
}


So i created a property called Focus on my ViewModelBase class with the exacte same type,  but for the return type of the function i take Object.

public abstract class ViewModelBase<T>
{
public Expression<Func<T,Object>> Focus { get; set; }
}
 

Then my PersonViewModel inherits from ViewModelBase<T> where T equals the PersonViewModel type. That way i have complete intellisence when i want to set the Focus property.

public class PersonViewModel : ViewModelBase<PersonViewModel>
{
public String Name { get; set; }

public String LastName { get; set; }
}

At the view side, i’ll use the GetId extension method to determine the id off the control i want to set the focus to.  I’ll pas the Focus property as parameter for this extension method. Then i’ll use it’s result in a JQuery selector and invoke the .focus() method.

@model ASP.NET_MVC_Set_Focus_ViewModel_Style.Models.PersonViewModel
@{
ViewBag.Title = "Index";
}
<h2>
Index</h2>
@using (Html.BeginForm())
{
<table>
<
tr>
<
td>
Name
</td>
<
td>
@Html.TextBoxFor(m => m.Name)
</td>
</
tr>
<
tr>
<
td>
Lastname
</td>
<
td>
@Html.TextBoxFor(m => m.LastName)
</td>
</
tr>
</
table>
@Html.HiddenFor(m => m.Focus)
<input type="submit" value="ChangeFocus" />
}
<script type="text/javascript">
$(document).ready(function () {
$("#@Html.GetId(Model.Focus)").focus();
});
</script>

At the Controller side, on the HttpGet method, i’ll set the focus on the Name. On the HttpPost method, i’ll set the focus on LastName. That way you’ll see the difference.

public class HomeController : Controller
{
[HttpGet]
public ActionResult Index()
{
var personViewModel = new PersonViewModel();

personViewModel.Focus = m => m.Name;

return View(personViewModel);
}

[HttpPost]
public ActionResult Index(PersonViewModel personViewModel)
{
personViewModel.Focus = m => m.LastName;

return View(personViewModel);
}
}

 


The main advantage is that you don’t have to work with those magic strings. When the property is renamed or removed, i’ll get a compiler error. And your code is cleaner.


This code isn’t rocket science but can be very handy. The solution can be downloaded from here.

Read more →