2013-05-25 10 views
16

Próbuję utworzyć niestandardowy segregator modelu dla MVC 4, który będzie dziedziczyć po DefaultModelBinder. Chciałbym, aby przechwytywał on wszelkie interfejsy na poziomie powiązaniai próbował załadować żądany typ z ukrytego pola o nazwie AssemblyQualifiedName.Spojrzenie na model niestandardowy dziedziczące z obiektu DefaultModelBinder

Oto co mam do tej pory (uproszczony):

public class MyWebApplication : System.Web.HttpApplication 
{ 
    protected void Application_Start() 
    { 
     ModelBinders.Binders.DefaultBinder = new InterfaceModelBinder(); 
    } 
} 

public class InterfaceModelBinder : DefaultModelBinder 
{ 
    public override object BindModel(ControllerContext controllerContext, 
     ModelBindingContext bindingContext) 
    { 
     if (bindingContext.ModelType.IsInterface 
      && controllerContext.RequestContext.HttpContext.Request.Form.AllKeys.Contains("AssemblyQualifiedName")) 
     { 
      ModelBindingContext context = new ModelBindingContext(bindingContext); 

      var item = Activator.CreateInstance(
       Type.GetType(controllerContext.RequestContext.HttpContext.Request.Form["AssemblyQualifiedName"])); 

      Func<object> modelAccessor =() => item; 
      context.ModelMetadata = new ModelMetadata(new DataAnnotationsModelMetadataProvider(), 
       bindingContext.ModelMetadata.ContainerType, modelAccessor, item.GetType(), bindingContext.ModelName); 

      return base.BindModel(controllerContext, context); 
     } 

     return base.BindModel(controllerContext, bindingContext); 
    } 
} 
plik

Przykład Create.cshtml (uproszczony):

@model Models.ScheduledJob 

@* Begin Form *@ 
@Html.Hidden("AssemblyQualifiedName", Model.Job.GetType().AssemblyQualifiedName) 

@Html.Partial("_JobParameters") 
@* End Form *@ 

Powyższy częściowy _JobParameters.cshtml patrzy na właściwościom Model.Job „s i buduje formanty edycji, podobne do @Html.EditorFor(), ale z dodatkowymi znacznikami. Właściwość ScheduledJob.Job jest typu IJob (interfejs).

Przykład ScheduledJobsController.cs (-i)

[HttpPost] 
public ActionResult Create(ScheduledJob scheduledJob) 
{ 
    //scheduledJob.Job here is not null, but has only default values 
} 

Kiedy zachować formę, interpretuje typ obiektu prawidłowo i pobiera nową instancję, ale właściwości obiektu nie są ustawione na właściwe wartości.

Co jeszcze muszę zrobić, aby powiadomić domyślny spinacz o przejęciu powiązania właściwości określonego typu?

Odpowiedz

21

This article pokazał mi, że zbyt mocno komplikowałem model spoiwa. Poniższy kod działa:

public class InterfaceModelBinder : DefaultModelBinder 
{ 
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) 
    { 
     if (bindingContext.ModelType.IsInterface) 
     { 
      Type desiredType = Type.GetType(
       EncryptionService.Decrypt(
        (string)bindingContext.ValueProvider.GetValue("AssemblyQualifiedName").ConvertTo(typeof(string)))); 
      bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, desiredType); 
     } 

     return base.BindModel(controllerContext, bindingContext); 
    } 
} 
+0

Skąd dodałeś powyższy segregator? Mam binder ModelBinders.Binders.Add (typeof (Organization), new OrganizationModelBinder (DependencyResolver.Current.GetService ())); na stronie global.asax.cs w metodzie App_start(). Poszukuję tylko lepszych sposobów rejestrowania segregatorów modeli, takich jak sposób trasowania i pakowania? – mmssaann

+0

@mmssaann Użyłem 'ModelBinders.Binders.DefaultBinder = new MyCustomModelBinder();' w global.asax.cs 'Application_Start()'. Następnie zrobiłem mój Generator ModelBinder wystarczająco ogólny, aby obsłużyć dowolną klasę abstrakcyjną lub interfejs, w przeciwnym razie przekazać logikę wiązania do DefaultModelBinder. –

1

z MVC 4 łatwo jest zastąpić wiadomości, jeśli to wszystko może być potrzebne w niestandardowym modelu spoiwa:

protected void Application_Start(object sender, EventArgs e) 
    { 
     //set mvc default messages, or language specifc 
     ClientDataTypeModelValidatorProvider.ResourceClassKey = "ValidationMessages"; 
     DefaultModelBinder.ResourceClassKey = "ValidationMessages"; 
    } 

Następnie należy utworzyć plik zasobów nazwie ValidationMessages z wpisy takie jak to:

NAME: FieldMustBeDate 
VALUE: The field {0} must be a date. 
NAME: FieldMustBeNumeric 
VALUE: The field {0} must be a number 

.

Zrobiliśmy to dla braku zgodności. Nasz skan bezpieczeństwa nie podobał się, że wtrysk wróci i pojawi się w komunikatach walidacyjnych i zostanie wykonany. Korzystając z tej implementacji, nadpisujemy domyślne komunikaty, które zwracają wartość dostarczoną przez użytkownika.

Powiązane problemy