2012-10-03 14 views
7

के लिए कस्टम मॉडल बाइंडर का उपयोग करके मैं एक मॉडल से इनपुट स्ट्रिंग वैरिएबल में एक POST से उपयोगकर्ता द्वारा इनपुट की गई HTML स्ट्रिंग को बाध्य करने का प्रयास कर रहा हूं। अगर मैं [AllowHtml] विशेषता का उपयोग करता हूं तो यह ठीक काम करता है। हालांकि, मैं एचटीएमएल स्वच्छ करना चाहते हैं इससे पहले कि यह मॉडल में अपनी राह बनाता तो मैं एक ModelBinder बनाया है:एचटीएमएल स्ट्रिंग्स

public class SafeHtmlModelBinder : DefaultModelBinder 
{ 
    public override object BindModel(ControllerContext controllerCtx, ModelBindingContext bindingCtx) 
    { 
     var bound = base.BindModel(controllerCtx, bindingCtx); 
     // TODO - return a safe HTML fragment string 
     return bound; 
    } 
} 

और यह भी एक CustomModelBinderAttribute:

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = false)] 
public class SafeHtmlModelBinderAttribute : CustomModelBinderAttribute 
{ 
    public SafeHtmlModelBinderAttribute() 
    { 
     binder = new SafeHtmlModelBinder(); 
    } 

    private IModelBinder binder; 

    public override IModelBinder GetBinder() 
    { 
     return binder; 
    } 
} 

मैं तो मॉडल गुण व्याख्या मैं नई विशेषता के साथ स्वच्छ होना चाहते हैं जो:

[Required(AllowEmptyStrings = false, ErrorMessage = "You must fill in your profile summary")] 
[AllowHtml, SafeHtmlModelBinder, WordCount(Min = 1, Max = 300)] 
public string Summary { get; set; } 

यह http://msdn.microsoft.com/en-us/magazine/hh781022.aspx में उदाहरण का पालन करना है। दुर्भाग्य से, यह काम नहीं लग रहा है! अगर मैं अपने BindModel विधि में ब्रेकपॉइंट डालता हूं तो यह कभी हिट नहीं होता है। कोई विचार?

अद्यतन

जानकारी जोएल से मैं अपने IModelBinder बदल दिया है जब SetProperty विधि में मूल्य रोकना और इसके बजाय क्लास वाली स्ट्रिंग गुण है कि HTML शामिल कर सकते हैं करने के लिए SafeHtmlModelBinderAttribute लागू के आधार पर। कोड की जाँच करता है कि संपत्ति के एक स्ट्रिंग है और यह भी साफ़ करने में प्रयास करने से पहले एचटीएमएल शामिल करने के लिए अनुमति दी है:

public class SafeHtmlModelBinder : DefaultModelBinder 
{ 
    protected override void SetProperty(
     ControllerContext controllerCtx, 
     ModelBindingContext bindingCtx, 
     PropertyDescriptor property, 
     object value) 
    { 
     var propertyIsString = property.PropertyType == typeof(string); 
     var propertyAllowsHtml = property.Attributes.OfType<AllowHtmlAttribute>().Count() >= 1; 

     var input = value as string; 
     if (propertyIsString && propertyAllowsHtml && input != null) 
     { 
      // TODO - sanitize HTML 
      value = input; 
     } 

     base.SetProperty(controllerCtx, bindingCtx, property, value); 
    } 
} 
+0

क्या कस्टममोडेलबिन्डर एट्रिब्यूट गुणों पर काम करते हैं?एमवीसी स्रोत कोड को देखते हुए विशेषता का उपयोग केवल 'आंतरिक कॉन्स विशेषताएँ लक्ष्य ValidTargets = विशेषताTargets.Class पर किया जाता है। विशेषता लक्ष्य। ज्ञान | विशेषता लक्ष्य। इंटरफेस | विशेषता लक्ष्य। पैरामीटर | विशेषता लक्ष्य। संरचना; '... जो मुझे बताता है कि ढांचे को गुणों पर यह देखने की उम्मीद नहीं है। – Schneider

उत्तर

1

मैं सिर्फ एक ही बात के साथ संघर्ष कर रहा हूँ। ऐसा लगता है जैसे GetBinder() विधि कभी नहीं कहा जाता है। चारों ओर खोदने के बाद मुझे this post मिला जहां स्वीकार्य उत्तर यह है कि किसी संपत्ति के लिए मॉडल बाध्यकारी विशेषता डालना संभव नहीं है।

चाहे यह सच है या नहीं, मुझे नहीं पता, लेकिन अभी के लिए मैं बस कोशिश करने और प्राप्त करने जा रहा हूं जो मुझे एक अलग तरीके से करने की ज़रूरत है। एक विचार अधिक सामान्य मॉडलबिंडर बनाना होगा और बाध्यकारी प्रदर्शन करते समय अपनी विशेषता की उपस्थिति की जांच करें, जैसा कि this answer में सुझाया जा रहा है।

1

मैं निम्नलिखित समाधान http://aboutcode.net/2011/03/12/mvc-property-binder.html काम करता है बहुत अच्छी तरह से

पहले से derrived आप एक सरल विशेषता है कि आप गुण

public class PropertyBinderAttribute : Attribute 
     { 
      public PropertyBinderAttribute(Type binderType) 
      { 
       BinderType = binderType; 
      } 

      public Type BinderType { get; private set; } 
     } 

निम्नलिखित मॉडल बांधने की मशीन के लिए आवेदन कर सकते हैं की जरूरत मिल गया है

public class DefaultModelBinder : System.Web.Mvc.DefaultModelBinder 
    { 
     protected override void BindProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor) 
     { 
      var propertyBinderAttribute = TryFindPropertyBinderAttribute(propertyDescriptor); 
      if (propertyBinderAttribute != null) 
      { 
       var binder = CreateBinder(propertyBinderAttribute); 
       binder.BindProperty(controllerContext, bindingContext, propertyDescriptor); 
      } 
      else // revert to the default behavior. 
      { 
       base.BindProperty(controllerContext, bindingContext, propertyDescriptor); 
      } 
     } 

     IPropertyBinder CreateBinder(PropertyBinderAttribute propertyBinderAttribute) 
     { 
      return (IPropertyBinder)DependencyResolver.Current.GetService(propertyBinderAttribute.BinderType); 
     } 

     PropertyBinderAttribute TryFindPropertyBinderAttribute(PropertyDescriptor propertyDescriptor) 
     { 
      return propertyDescriptor.Attributes.OfType<PropertyBinderAttribute>().FirstOrDefault(); 
     } 
    } 

को ग्लोबल.एएसएक्स सीएस

में ओवरराइड किया गया है
ModelBinders.Binders.DefaultBinder = new DefaultModelBinder(); 

फिर अपने मॉडल को बांधने की मशीन बनाने

public class InvariantCultureDecimalModelBinder : IModelBinder, IPropertyBinder 
    { 
     public void BindProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor) 
     { 
      var subPropertyName = CreateSubPropertyName(bindingContext.ModelName, propertyDescriptor.Name); 
      if (!bindingContext.ValueProvider.ContainsPrefix(subPropertyName)) 
       return; 

      var attemptedValue = bindingContext.ValueProvider.GetValue(subPropertyName).AttemptedValue; 
      if (String.IsNullOrEmpty(attemptedValue)) 
       return; 

      object actualValue = null; 
      try 
      { 
       actualValue = Convert.ToDecimal(attemptedValue, CultureInfo.InvariantCulture); 
      } 
      catch (FormatException e) 
      { 
       bindingContext.ModelState[propertyDescriptor.Name].Errors.Add(e); 
      } 

      propertyDescriptor.SetValue(bindingContext.Model, actualValue); 
     } 

     public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) 
     { 
      var valueResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName); 
      var modelState = new ModelState { Value = valueResult }; 
      object actualValue = null; 
      try 
      { 
       if (!String.IsNullOrEmpty(valueResult.AttemptedValue)) 
        actualValue = Convert.ToDecimal(valueResult.AttemptedValue, CultureInfo.InvariantCulture); 
      } 
      catch (FormatException e) 
      { 
       modelState.Errors.Add(e); 
      } 

      bindingContext.ModelState.Add(bindingContext.ModelName, modelState); 
      return actualValue; 
     } 

     //Duplicate code exits in DefaulModelBinder but it is protected internal 
     private string CreateSubPropertyName(string prefix, string propertyName) 
     { 
      if (string.IsNullOrEmpty(prefix)) 
       return propertyName; 
      if (string.IsNullOrEmpty(propertyName)) 
       return prefix; 
      else 
       return prefix + "." + propertyName; 
     } 

    } 

जो अब सफाई से मॉडल गुण

[PropertyBinder(typeof(InvariantCultureDecimalModelBinder))] 
public decimal? value 

या प्रयोग पर एक मानक तरीके से लागू किया जा सकता निर्मित मानकों के आधार पर विशेषता

public ActionResult DoSomething([ModelBinder(typeof(InvariantCultureDecimalModelBinder))] decimal value) 
संबंधित मुद्दे