自定义模型Binder,asp.net mvc 2 rtm 2,将ID解析为ComplexModel

时间:2010-06-10 20:25:20

标签: asp.net-mvc-2

我发现自己遇到了一些问题,我认为自定义模型绑定器是可行的方法。

My Domain模型看起来像这样,读标准 我有一个页面和一个模板。页面将模板作为参考。 所以默认的asp.net mvc 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; }
}

所以我在globals.asax中注册了ModelBinder

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是我的存储库,我获取所有实体(页面,模板)

我的页面控制器看起来像这样。 我已经发布了一个Create Controler,它现在没关系,如果它是Update方法。 由于我在这种情况下有一个下拉列表,代表模板,我将在我的表单集合中获得一个ID。

然后我调用:TryUpdateModel,我的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);
}

所以我用模型Binder结束了操作。 我已经在互联网上搜索干燥的信息,但我有库存。

我需要从FormCollection中获取ID,并从IEntityStore将其解析为Model。 但是怎么样?

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 ??
        }
    }

}

//丹尼斯

我希望,我的问题很清楚。

1 个答案:

答案 0 :(得分:0)

找到了解决方法。 我下载了asp.net r2 rtm 2的源代码

并且复制了默认ModelBinder的所有代码,并且需要编码。做了一些小改动,小黑客。

这种解决方法在这种方法上做了一点点破解:

[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;
            }
        }
    }

这个问题已经结束。