You are currently browsing the category archive for the ‘MVC’ category.

I need to pass a model to an ASP.NET MVC view, declaring it as ‘dynamic’. The model is populated (via controller) by another class in another assembly. I use ‘dynamic’ keyword, because it is an anonymous type (in general). Problem: anonymous types are INTERNAL (read it on http://blogs.msdn.com/b/davidebb/archive/2009/12/18/passing-anonymous-objects-to-mvc-views-and-accessing-them-using-dynamic.aspx) and views in ASP.NET MVC are dynamically compiled into another assembly.

So in general when you pass an instance of an anonymous type in an ASP.NET MVC view, you cannot see it and you have an object instead and you don’t access you members.

The solution? Use ExpandoObject. Instead of:

   1:   dynamic obj = new
   2:                  {
   3:                      ID = item.ID
   4:                      ,
   5:                      Text = text
   6:                      ,
   7:                      Type = item.Type
   8:                      ,
   9:                      Path = pathOf + "/" + text
  10:                  };

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }


use

   1:  dynamic obj = new ExpandoObject();
   2:                  obj.ID = item.ID;
   3:                  obj.Text = text;
   4:                  obj.Type = item.Type;
   5:                  obj.Path = pathOf + "/" + text;

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

 

ExpandoObject is a public type that comes from DLR (like CallSites that allow us to use dynamic keywork in C#). It has the ability to add members at runtime, that are then accessible via dynamic keywork.

Enjoy!

I’m writing a CMS in ASP.NET MVC. One of my needs is that in a custom CRUD cycle, I can use different entities, all inherited from a base class. Because of default model binder, an action method must be of the specific type to deserialize information from the form collection into the entity. The persistence is based on generic XML serialization: how to locate the serialization is due to url information(s).

This is one of my action methods:

        [AcceptVerbs(HttpVerbs.Post)]
        [ValidateInput(false)]
        public ActionResult UpdateResource(string path, ICMSResourceInfo resource)
        {
            var instance = DataContext.Get(path);
            if (instance == null)
                return RedirectToError("Istanza da aggiornare non trovata");

            instance.Serialize(resource);

            SaveChanges();

            return RedirectToBrowse(resource.Parent);
        }

How to do it?

I have some information in the POST action, for example a “resource.TemplateName” that I use to specify the Type. This information can be used in a custom DefaultModelBinder to decide which type instantiate.

DefaultModelBinder has a method named BindModel:

        public override object BindModel(ControllerContext controllerContext, 
ModelBindingContext bindingContext)

BindModel has an argument, named bindingContext of type ModelBindingContext:

namespace System.Web.Mvc
{
    public class ModelBindingContext
    {
        //…
        public Type ModelType { get; set; }
        public IDictionary<string, ValueProviderResult> ValueProvider { get; set; }
    }
}

Two properties are interesting for our needs.

BindingContext contains the property ValueProvider which is a Dictionary that is really the FormCollection we can use in Action method. If we override BindModel method in a class derived from ModelBinder,we can find in ValueProvider our “resource.TemplateName” value.

The second is ModelType: this is the type that the DefaultModelBinder has obtained from Action method. So, if we decide that some values in ValueProvider (“resource.TemplateName” in my case) has some values, I can change the ModelType. Specifically:

    public class CMSModelBinder: DefaultModelBinder
    {
        public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
            if (bindingContext.ValueProvider.ContainsKey("resource.TemplateName"))
            {
                bindingContext.ModelType =
                    CMSTemplateFactory.Default.GetTypeOf(
                        bindingContext.ValueProvider["resource.TemplateName"].AttemptedValue);
                // CMSFolderTemplateFactory is a class in which I map my custom types (templates)
            }
            var bound = base.BindModel(controllerContext, bindingContext);
            return bound;
        }

So, bindingContext.ValueProvider["resource.TemplateName"].AttemptedValue is the key I use to decode my specifc type. I obtain (in some ways) the specific type and then DefaultModelBinder continue with its work.

To declare to ASP.NET MVC that there is a new ModelBinder, in Global.asax we need to declare:

            CMSModelBinder modelBinder = 
                new CMSModelBinder();

            ModelBinders.Binders[typeof(ICMSResourceInfo)] = modelBinder;

In general, we have to associate a ModelBinder for each specific type we need to specify a custom binding.

Inheritance is not considered: binding associate on specific types. This means that if I write:

            ModelBinders.Binders[typeof(object)] = modelBinder;

this assiociation is valid for an Action method with arguments of object type, not every type inherited from object (all!!!)

I think this is good, not bad.

Enjoy!

     Marco

This evening, with my dear friend Manuel for the Pordenone group 1nn0va, I have presented ASP.NET MVC framework to a small, but very interested, group of people.

The interesting content  of the presentation was the focus on MVC in general, looking at ASP.NET MVC as an implementation, but also MonoRail as another implementation.

The fun part was the preparation of the presentation. The demo was a web application on the AdventureWorks DB. I have told to Manuel to prepare the demo in MonoRail (with NVelocity view engine); then I have converted it.

Well, the things to be changed to make the application functioning under ASP.NET MVC were very few. This tells me that ASP.NET MVC is really a Microsoft “product”: learn from the community, embrace and extend.

You can download slides and demo code (the code file is really a zip file – I have appended a .pdf file because WordPress, my blog host, does not allow me to upload zip files).

Very nice.

Marco

My tweets

Follow

Get every new post delivered to your Inbox.