views:

60

answers:

1

I have found myself with at little problem, and I think a custom model binder is the way to go.

My Domain model looks like this,readly standard I got a Page and a Template. The Page has the Template as a ref. So the Default asp.net mvc Binder, does not know how to bind it, therefore I need to make some rules for it. (Custom Model Binder)

public class PageTemplate
{
    public virtual string Title { get; set; }
    public virtual string Content { get; set; }
    public virtual DateTime? Created { get; set; }
    public virtual DateTime? Modified { get; set; }
}



public class Page
{
    public virtual string Title { get; set; }
    public virtual PageTemplate Template { get; set; }
    public virtual string Content { get; set; }
    public virtual DateTime? Created { get; set; }
    public virtual DateTime? Modified { get; set; }
}

So I have Registreted the ModelBinder in globals.asax

ModelBinders.Binders.Add(typeof(Cms.Domain.Entities.Page),
                        new Cms.UI.Web.App.ModelBinders.PageModelBinder(
                                new Services.GenericApplicationService<Cms.Domain.Entities.Page>().GetEntityStore()
                            )
                        );

My ModelBinder tage a paremeter, witch is my Repository, where I get all my Entities ( Page, Template )

My Controller for a Page looks like this. I have posted into a Create Controler, it does not matter for now, if it was a Update method. Since I in this case have a dropdown, that represents the Template, I will get an ID in my form collection.

I then call: TryUpdateModel and I got a hit in my PageModelBinder.

[AcceptVerbs(HttpVerbs.Post), ValidateAntiForgeryToken]
[ValidateInput(false)]
public ActionResult Create(FormCollection form)
{
    Page o = new Page();

    string[] exclude = new { "Id" }
    if (base.TryUpdateModel<Page>(o, string.Empty, null, exclude, form.ToValueProvider()))
    {
        if (ModelState.IsValid)
        {
            this.PageService.Add(o);
            this.CmsViewData.PageList = this.PageService.List();
            this.CmsViewData.Messages.AddMessage("Page is updated.", MessageTypes.Succes);
            return View("List", this.CmsViewData);
        }
    }

    return View("New", this.CmsViewData);
}

So I end op with the Model Binder. I have search the internet dry for information, but im stock.

I need to get the ID from the FormCollection, and parse it to at Model from my IEntityStore. But how ?

public class PageModelBinder : IModelBinder
{

    public readonly IEntityStore RepositoryResolver;

    public PageModelBinder(IEntityStore repositoryResolver)
    {
        this.RepositoryResolver = repositoryResolver;
    }

    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        if (bindingContext == null)
        {
            throw new ArgumentNullException("bindingContext");
        }

        if (modelType == typeof(Cms.Domain.Entities.Page))
        {
            // Do some magic 
            // Get the Id from Property and bind it to model, how ??
        }
    }

}

// Dennis

I hope, my problom is clear.

A: 

Did find a work around. I download the sourcecode for asp.net r2 rtm 2

And did copy all code for the default ModelBinder, and code it need. Did some minor change, small hacks.

the work around is doing a little hack in this method:

[SuppressMessage("Microsoft.Globalization", "CA1304:SpecifyCultureInfo", MessageId = "System.Web.Mvc.ValueProviderResult.ConvertTo(System.Type)",
        Justification = "The target object should make the correct culture determination, not this method.")]
    [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes",
        Justification = "We're recording this exception so that we can act on it later.")]
    private static object ConvertProviderResult(ModelStateDictionary modelState, string modelStateKey, ValueProviderResult valueProviderResult, Type destinationType)
    {
        try
        {
            object convertedValue = valueProviderResult.ConvertTo(destinationType);
            return convertedValue;
        }
        catch (Exception ex)
        {
            try
            {
                // HACK if the binder still fails, try get the entity in db.
                Services.GenericApplicationService<Cms.Domain.Entities.PageTemplate> repo;
                repo = new Services.GenericApplicationService<Cms.Domain.Entities.PageTemplate>();
                int id = Convert.ToInt32(valueProviderResult.AttemptedValue);
                object convertedValue = repo.Retrieve(id);
                return convertedValue;
            }
            catch (Exception ex1)
            {
                modelState.AddModelError(modelStateKey, ex1);
                return null;
            }
        }
    }

This question is closed.

Dennis Larsen