डेटा प्रविष्टि के बाद तार को ट्रिम करने का सबसे अच्छा तरीका। क्या मुझे एक कस्टम मॉडल बाइंडर बनाना चाहिए?


172

मैं ASP.NET MVC का उपयोग कर रहा हूं और मैं चाहूंगा कि डेटाबेस में सम्मिलित होने से पहले सभी उपयोगकर्ता स्ट्रिंग फ़ील्ड में ट्रिम किए जाएं। और जब से मेरे पास कई डेटा एंट्री फॉर्म हैं, मैं स्पष्ट रूप से ट्रिमिंग करने वाले प्रत्येक उपयोगकर्ता को स्ट्रिंग मान के बजाय सभी स्ट्रिंग्स को ट्रिम करने के लिए एक सुरुचिपूर्ण तरीके की तलाश कर रहा हूं। मुझे यह जानने में दिलचस्पी है कि लोग कैसे और कब तार काट रहे हैं।

मैंने शायद एक कस्टम मॉडल बाइंडर बनाने और वहां किसी भी स्ट्रिंग मान को ट्रिम करने के बारे में सोचा था ... उस तरह से, मेरे सभी ट्रिमिंग तर्क एक ही स्थान पर निहित हैं। क्या यह एक अच्छा तरीका है? क्या कोई कोड नमूने हैं जो ऐसा करते हैं?

जवाबों:


214
  public class TrimModelBinder : DefaultModelBinder
  {
    protected override void SetProperty(ControllerContext controllerContext, 
      ModelBindingContext bindingContext, 
      System.ComponentModel.PropertyDescriptor propertyDescriptor, object value)
    {
      if (propertyDescriptor.PropertyType == typeof(string))
      {
        var stringValue = (string)value;
        if (!string.IsNullOrWhiteSpace(stringValue))
        {
          value = stringValue.Trim();
        }
        else
        {
          value = null;
        }
      }

      base.SetProperty(controllerContext, bindingContext, 
                          propertyDescriptor, value);
    }
  }

इस कोड के बारे में कैसे?

ModelBinders.Binders.DefaultBinder = new TrimModelBinder();

Global.asax Application_Start ईवेंट सेट करें।


3
मैं केवल सबसे अधिक {} में कोड को संक्षिप्तता के लिए इसके साथ प्रतिस्थापित करूंगा: string stringValue = (string) value; मान = string.sNullOrEmpty (stringValue)? stringValue: stringValue.Trim ();
साइमन_वेअर

4
यह अधिक उत्थान के योग्य है। मुझे वास्तव में आश्चर्य है कि MVC टीम ने इसे डिफ़ॉल्ट मॉडल बाइंडर में लागू करने का विकल्प नहीं चुना ...
पोर्टमैन

1
@BreckFresen मुझे भी यही समस्या थी, आपको BindModel मेथड को ओवरराइड करने और बाइंडिंग कॉन्टेक्स्ट की जांच करने की आवश्यकता होगी। एक स्ट्रिंग के लिएodelType फिर इसे ट्रिम करें।
केली

3
मेरे जैसे किसी को भी DefaultModelBinder पर अस्पष्टता मिलने पर, सही व्यक्ति System.Web.Mvc का उपयोग कर रहा है।
ज्योफएम

3
आप इससे type="password"अछूते इनपुट को छोड़ने के लिए इसे कैसे संशोधित करेंगे ?
एक्सट्रागोरे

77

यह @takepara समान रिज़ॉल्यूशन है, लेकिन DefaultModelBinder के बजाय IModelBinder के रूप में, ताकि ग्लोबल में मॉडलबिंडर जोड़ना हो।

ModelBinders.Binders.Add(typeof(string),new TrimModelBinder());

कक्षा:

public class TrimModelBinder : IModelBinder
{
    public object BindModel(ControllerContext controllerContext,
    ModelBindingContext bindingContext)
    {
        ValueProviderResult valueResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
        if (valueResult== null || valueResult.AttemptedValue==null)
           return null;
        else if (valueResult.AttemptedValue == string.Empty)
           return string.Empty;
        return valueResult.AttemptedValue.Trim();
    }
}

@haacked पोस्ट के आधार पर: http://haacked.com/archive/2011/03/19/fixing-binding-to-decimals.aspx


1
एक स्वच्छ समाधान के लिए +1! आप returnबयानों के क्रम को बदलकर और शर्त को नकार कर अपने कोड की पठनीयता को और अधिक बेहतर बना सकते हैं:if (valueResult == null || string.IsNullOrEmpty(valueResult.AttemptedValue)) return null;
Marius Schulz

6
यह [ValidateInput (झूठी)] नियंत्रक विशेषता को संभालता नहीं है। यह "खतरनाक अनुरोध ..." अपवाद का कारण बनता है।
कोडग्रे

2
जिन लोगों को 'डेंजरस रिक्वेस्ट ...' अपवाद मिल रहा है, उनके लिए इस लेख का संदर्भ लें - blogs.taiga.nl/martijn/2011/09/29/…
GurjeetSinghDB

2
: मेरा एक सहकर्मी इस का एक परिवर्तन है कि मुद्दों के सभी प्रकार की वजह से लागू किया issues.umbraco.org/issue/U4-6665 मैं अशक्त लौटने की सलाह देते हैं और हमेशा एक दूसरे के ऊपर पसंद करते हैं बजाय के रूप में उपयुक्त खाली (आपके मामले में होता है, आप हमेशा शून्य वापसी तब भी करें जब मूल्य एक रिक्त स्ट्रिंग है)।
निकोलस वेस्टबी

2
यह [AllowHtml]मॉडल गुणों पर विशेषता को तोड़ने के लिए लगता है ( [ValidateInput(false)]जैसा कि ऊपर उल्लिखित कोडग्रे के साथ है
सेमुअल

43

@Takepara जवाब में एक सुधार।

परियोजना में कहीं:

public class NoTrimAttribute : Attribute { }

TrimModelBinder वर्ग परिवर्तन में

if (propertyDescriptor.PropertyType == typeof(string))

सेवा

if (propertyDescriptor.PropertyType == typeof(string) && !propertyDescriptor.Attributes.Cast<object>().Any(a => a.GetType() == typeof(NoTrimAttribute)))

और आप [NoTrim] विशेषता के साथ ट्रिमिंग से बाहर किए जाने के लिए गुणों को चिह्नित कर सकते हैं।


1
हम @Korayem द्वारा IModelBinder दृष्टिकोण का उपयोग करते समय इस तरह की विशेषता को कैसे लागू कर सकते हैं? कुछ अनुप्रयोगों में, मैं एक अलग (तृतीय-पक्ष) मॉडल बाइंडर का उपयोग करता हूं (जैसे, एस # आरपी आर्किटेक्योर का)। मैं इसे परियोजनाओं के बीच साझा एक निजी DLL में लिखना चाहता हूं, इसलिए इसे IModelBinder दृष्टिकोण की आवश्यकता है।
कार्ल बुसिमा

1
@CarlBussema यहाँ एक IModelBinder के भीतर से गुण तक पहुँचने के बारे में एक सवाल है। stackoverflow.com/questions/6205176
मैक अटैक

4
मुझे लगता है कि यह एक बढ़िया अतिरिक्त है लेकिन मैं इसके .Cast<object>().Any(a => a.GetType() == typeof(NoTrimAttribute))साथ बदलूंगा .OfType<NoTrimAttribute>().Any()। बस थोड़ा सा क्लीनर।
DBueno

मैंने अपनी विशेषताओं को एक साझा असेंबली में रखा, क्योंकि डेटा एनोटेशन के साथ, इस तरह की विशेषताओं का उपयोग केवल एमवीसी, जैसे व्यापार स्तरीय, ग्राहकों से व्यापक है। एक अन्य अवलोकन, "DisplayFormatAttribute (ConvertEmptyStringToNull)" नियंत्रित करता है कि छंटनी की गई स्ट्रिंग को रिक्त या रिक्त स्ट्रिंग के रूप में सहेजा जाएगा या नहीं। डिफ़ॉल्ट सत्य (अशक्त) है जो मुझे पसंद है लेकिन अगर आपको अपने डेटाबेस में खाली तारों की आवश्यकता होती है (उम्मीद है कि नहीं) तो आप इसे प्राप्त करने के लिए गलत सेट कर सकते हैं। वैसे भी, यह सब अच्छा सामान है, आशा है कि एमएस अपनी विशेषताओं का विस्तार करके ट्रिमिंग और पैडिंग और इस तरह के बहुत सारे अन्य सामान शामिल कर सकते हैं।
टोनी वॉल

17

C # 6 में सुधार के साथ, अब आप एक बहुत कॉम्पैक्ट मॉडल बाइंडर लिख सकते हैं जो सभी स्ट्रिंग इनपुट को ट्रिम कर देगा:

public class TrimStringModelBinder : IModelBinder
{
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var value = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
        var attemptedValue = value?.AttemptedValue;

        return string.IsNullOrWhiteSpace(attemptedValue) ? attemptedValue : attemptedValue.Trim();
    }
}

बाइंडिंग s के दौरान मॉडल बाइंडर का उपयोग करने के लिए आपको इस लाइन Application_Start()को अपनी Global.asax.csफ़ाइल में कहीं न कहीं शामिल करना होगा string:

ModelBinders.Binders.Add(typeof(string), new TrimStringModelBinder());

मुझे लगता है कि डिफ़ॉल्ट मॉडल बाइंडर को ओवरराइड करने के बजाय, इस तरह के मॉडल बाइंडर का उपयोग करना बेहतर होता है, क्योंकि तब इसका उपयोग तब किया जाएगा जब आप एक बाध्यकारी हैं string, चाहे वह सीधे तौर पर एक विधि तर्क के रूप में हो या मॉडल वर्ग पर एक संपत्ति के रूप में हो। हालाँकि, यदि आप डिफ़ॉल्ट मॉडल बाइंडर को ओवरराइड करते हैं, जैसा कि यहां दिए गए अन्य उत्तरों से पता चलता है, यह केवल तभी काम करेगा जब मॉडल पर संपत्तियों को बाइंड किया जाएगा, न कि जब आपके पास stringएक्शन विधि के तर्क के रूप में हो

संपादित करें: एक टिप्पणीकार ने उस स्थिति से निपटने के बारे में पूछा जब किसी क्षेत्र को मान्य नहीं किया जाना चाहिए। ओपी ने जो सवाल किया था, उससे निपटने के लिए मेरा मूल उत्तर कम हो गया था, लेकिन जो लोग रुचि रखते हैं, आप निम्नलिखित विस्तारित मॉडल बाइंडर का उपयोग करके सत्यापन से निपट सकते हैं:

public class TrimStringModelBinder : IModelBinder
{
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var shouldPerformRequestValidation = controllerContext.Controller.ValidateRequest && bindingContext.ModelMetadata.RequestValidationEnabled;
        var unvalidatedValueProvider = bindingContext.ValueProvider as IUnvalidatedValueProvider;

        var value = unvalidatedValueProvider == null ?
          bindingContext.ValueProvider.GetValue(bindingContext.ModelName) :
          unvalidatedValueProvider.GetValue(bindingContext.ModelName, !shouldPerformRequestValidation);

        var attemptedValue = value?.AttemptedValue;

        return string.IsNullOrWhiteSpace(attemptedValue) ? attemptedValue : attemptedValue.Trim();
    }
}

फिर, ऊपर टिप्पणी देखें। यह उदाहरण IUnvalidatedValueProvider के SkipValidation आवश्यकता को संभालता नहीं है।
एरोन हुडोन

@adrian, IModelBinder इंटरफ़ेस में केवल BindModel की विधि है जिसमें रिटर्न टाइप बूल है। फिर आपने यहां रिटर्न टाइप ऑब्जेक्ट के साथ कैसे इस्तेमाल किया?
मगेंद्रन वी

@MagendranV मुझे यकीन नहीं है कि आप किस इंटरफ़ेस को देख रहे हैं, लेकिन यह उत्तर ASP.NET MVC 5 में IModelBinder पर आधारित है, जो एक वस्तु लौटाता है: docs.microsoft.com/en-us/prepret-versions/aspnet /…
एड्रियन

1
@AaronHudon ने अपने जवाब को अपडेट कर दिया है जिसमें स्किपिंग वेलिडेशन को संभालने के लिए एक उदाहरण शामिल है
एड्रियन

यदि आपके पासवर्ड फ़ील्ड में सही डेटाटाइप सेट है (यानी [DataType (DataType.Password)]) तो आप अंतिम पंक्ति को निम्नानुसार अपडेट कर सकते हैं ताकि यह इन फ़ील्ड्स को ट्रिम न करें: string string .sNullOrWhiteSpace (tryedValue) || बाइंडिंगटेक्स्ट.मॉडल मीटडाटा.डाटा टाइपनेम == "पासवर्ड"? tryedValue: tryedValue.Trim ();
ट्रफलेट

15

में ASP.Net कोर 2 यह मेरे लिए काम किया। मैं [FromBody]अपने नियंत्रकों और JSON इनपुट में विशेषता का उपयोग कर रहा हूं । JSON डिसेरलाइज़ेशन में स्ट्रिंग हैंडलिंग को ओवरराइड करने के लिए मैंने अपना JsonConverter पंजीकृत किया:

services.AddMvcCore()
    .AddJsonOptions(options =>
        {
            options.SerializerSettings.Converters.Insert(0, new TrimmingStringConverter());
        })

और यह कनवर्टर है:

public class TrimmingStringConverter : JsonConverter
{
    public override bool CanRead => true;
    public override bool CanWrite => false;

    public override bool CanConvert(Type objectType) => objectType == typeof(string);

    public override object ReadJson(JsonReader reader, Type objectType,
        object existingValue, JsonSerializer serializer)
    {
        if (reader.Value is string value)
        {
            return value.Trim();
        }

        return reader.Value;
    }

    public override void WriteJson(JsonWriter writer, object value,
        JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

आपका समाधान ठीक काम करता है! धन्यवाद। मैंने IMODelBinderProvider का उपयोग करके .Net कोर के लिए अन्य समाधानों की कोशिश की, यह काम नहीं किया।
सेड्रिक अर्नोल्ड

स्टार्टअप.के अलावा, इसे मॉडल में [JsonConverter (टाइपोफ़ (ट्रिमिंगस्ट्रिंगकॉनवर्टर))] के रूप में भी इस्तेमाल किया जा सकता है। Btw। वहाँ का उपयोग करने के पीछे एक कारण है। () बजाय .Add ()?
रहता या

@ मुझे लगता है कि मैंने ऐसा किया है। अन्य कन्वर्टर्स से पहले इसे चलाने के लिए .Add () के बजाय .Add () को सुनिश्चित करें। अब याद नहीं कर सकते।
काई जी

DefaultContractResolver पर इस प्रदर्शन का ओवरहेड क्या है?
मौलिक मोदी

13

@ टेकपारा के उत्तर का एक और प्रकार लेकिन एक अलग मोड़ के साथ:

1) मैं ऑप्ट-इन "StringTrim" विशेषता तंत्र को पसंद करता हूं (@Anton के ऑप्ट-आउट "NoTrim" उदाहरण के बजाय)।

2) मॉडलस्टोर को सही ढंग से आबाद करने के लिए सेटमॉडेलवैल्यू के लिए एक अतिरिक्त कॉल की आवश्यकता है और डिफ़ॉल्ट सत्यापन / स्वीकार / अस्वीकार पैटर्न को सामान्य के रूप में उपयोग किया जा सकता है, अर्थात सभी परिवर्तनों को स्वीकार करने के लिए और मॉडलस्टैट.क्लेयर () लागू करने के लिए ट्राइअपडेटमेटमॉडल (मॉडल)।

इसे अपनी इकाई / साझा पुस्तकालय में रखें:

/// <summary>
/// Denotes a data field that should be trimmed during binding, removing any spaces.
/// </summary>
/// <remarks>
/// <para>
/// Support for trimming is implmented in the model binder, as currently
/// Data Annotations provides no mechanism to coerce the value.
/// </para>
/// <para>
/// This attribute does not imply that empty strings should be converted to null.
/// When that is required you must additionally use the <see cref="System.ComponentModel.DataAnnotations.DisplayFormatAttribute.ConvertEmptyStringToNull"/>
/// option to control what happens to empty strings.
/// </para>
/// </remarks>
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
public class StringTrimAttribute : Attribute
{
}

फिर यह आपके MVC एप्लिकेशन / लाइब्रेरी में:

/// <summary>
/// MVC model binder which trims string values decorated with the <see cref="StringTrimAttribute"/>.
/// </summary>
public class StringTrimModelBinder : IModelBinder
{
    /// <summary>
    /// Binds the model, applying trimming when required.
    /// </summary>
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        // Get binding value (return null when not present)
        var propertyName = bindingContext.ModelName;
        var originalValueResult = bindingContext.ValueProvider.GetValue(propertyName);
        if (originalValueResult == null)
            return null;
        var boundValue = originalValueResult.AttemptedValue;

        // Trim when required
        if (!String.IsNullOrEmpty(boundValue))
        {
            // Check for trim attribute
            if (bindingContext.ModelMetadata.ContainerType != null)
            {
                var property = bindingContext.ModelMetadata.ContainerType.GetProperties()
                    .FirstOrDefault(propertyInfo => propertyInfo.Name == bindingContext.ModelMetadata.PropertyName);
                if (property != null && property.GetCustomAttributes(true)
                    .OfType<StringTrimAttribute>().Any())
                {
                    // Trim when attribute set
                    boundValue = boundValue.Trim();
                }
            }
        }

        // Register updated "attempted" value with the model state
        bindingContext.ModelState.SetModelValue(propertyName, new ValueProviderResult(
            originalValueResult.RawValue, boundValue, originalValueResult.Culture));

        // Return bound value
        return boundValue;
    }
}

यदि आप बाइंडर में संपत्ति का मूल्य निर्धारित नहीं करते हैं, तब भी जब आप कुछ भी बदलना नहीं चाहते हैं, तो आप उस संपत्ति को पूरी तरह से मॉडलस्टेट से ब्लॉक कर देंगे! ऐसा इसलिए है क्योंकि आप सभी स्ट्रिंग प्रकारों को बाइंड करने के रूप में पंजीकृत हैं, इसलिए ऐसा प्रतीत होता है (मेरे परीक्षण में) कि डिफ़ॉल्ट बाइंडर आपके लिए ऐसा नहीं करेगा।


7

ASP.NET Core 1.0 में ऐसा करने की खोज करने वाले किसी व्यक्ति के लिए अतिरिक्त जानकारी। लॉजिक काफी बदल गया है।

मैंने इसे कैसे करना है के बारे में एक ब्लॉग पोस्ट लिखा है , यह चीजों को थोड़ा और विस्तृत रूप से बताता है

तो ASP.NET Core 1.0 समाधान:

वास्तविक ट्रिमिंग करने के लिए मॉडल बांधने की मशीन

public class TrimmingModelBinder : ComplexTypeModelBinder  
{
    public TrimmingModelBinder(IDictionary propertyBinders) : base(propertyBinders)
    {
    }

    protected override void SetProperty(ModelBindingContext bindingContext, string modelName, ModelMetadata propertyMetadata, ModelBindingResult result)
    {
        if(result.Model is string)
        {
            string resultStr = (result.Model as string).Trim();
            result = ModelBindingResult.Success(resultStr);
        }

        base.SetProperty(bindingContext, modelName, propertyMetadata, result);
    }
}

इसके अलावा आपको नवीनतम संस्करण में मॉडल बाइंडर प्रदाता की आवश्यकता है, यह बताता है कि इस मॉडल के लिए इस बाइंडर का उपयोग किया जाना चाहिए

public class TrimmingModelBinderProvider : IModelBinderProvider
{
    public IModelBinder GetBinder(ModelBinderProviderContext context)
    {
        if (context == null)
        {
            throw new ArgumentNullException(nameof(context));
        }

        if (context.Metadata.IsComplexType && !context.Metadata.IsCollectionType)
        {
            var propertyBinders = new Dictionary();
            foreach (var property in context.Metadata.Properties)
            {
                propertyBinders.Add(property, context.CreateBinder(property));
            }

            return new TrimmingModelBinder(propertyBinders);
        }

        return null;
    }
}

फिर इसे Startup.cs में पंजीकृत करना होगा

 services.AddMvc().AddMvcOptions(options => {  
       options.ModelBinderProviders.Insert(0, new TrimmingModelBinderProvider());
 });

यह मेरे लिए भी काम नहीं करता है, मेरे सभी क्षेत्र अब शून्य हैं
सेड्रिक अर्नोल्ड

5

ऊपर दिए गए उत्कृष्ट उत्तरों और टिप्पणियों के माध्यम से पढ़ते हुए, और तेजी से भ्रमित होते हुए, मैंने अचानक सोचा, अरे, मुझे आश्चर्य है कि क्या कोई jQuery समाधान है। तो दूसरों के लिए, जो मेरे जैसे, मॉडलबाइंडर्स को थोड़ा आश्चर्यचकित करते हैं, मैं निम्नलिखित jQuery स्निपेट की पेशकश करता हूं जो फॉर्म सबमिट होने से पहले इनपुट फ़ील्ड को ट्रिम करता है।

    $('form').submit(function () {
        $(this).find('input:text').each(function () {
            $(this).val($.trim($(this).val()));
        })
    });

1
2 चीजें: 1 - अपने क्लाइंट ऑब्जेक्ट (जैसे $ (यह)) को कैश करें, 2 - आप कभी भी क्लाइंट इनपुट पर भरोसा नहीं कर सकते, लेकिन आप सर्वर कोड पर निश्चित रूप से भरोसा कर सकते हैं। तो आपका जवाब सर्वर कोड के जवाबों का पूरा होना है :)
graumanoz

5

एमवीसी कोर के मामले में

जिल्दसाज़:

using Microsoft.AspNetCore.Mvc.ModelBinding;
using System;
using System.Threading.Tasks;
public class TrimmingModelBinder
    : IModelBinder
{
    private readonly IModelBinder FallbackBinder;

    public TrimmingModelBinder(IModelBinder fallbackBinder)
    {
        FallbackBinder = fallbackBinder ?? throw new ArgumentNullException(nameof(fallbackBinder));
    }

    public Task BindModelAsync(ModelBindingContext bindingContext)
    {
        if (bindingContext == null)
        {
            throw new ArgumentNullException(nameof(bindingContext));
        }

        var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);

        if (valueProviderResult != null &&
            valueProviderResult.FirstValue is string str &&
            !string.IsNullOrEmpty(str))
        {
            bindingContext.Result = ModelBindingResult.Success(str.Trim());
            return Task.CompletedTask;
        }

        return FallbackBinder.BindModelAsync(bindingContext);
    }
}

प्रदाता:

using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.ModelBinding.Binders;
using System;

public class TrimmingModelBinderProvider
    : IModelBinderProvider
{
    public IModelBinder GetBinder(ModelBinderProviderContext context)
    {
        if (context == null)
        {
            throw new ArgumentNullException(nameof(context));
        }

        if (!context.Metadata.IsComplexType && context.Metadata.ModelType == typeof(string))
        {
            return new TrimmingModelBinder(new SimpleTypeModelBinder(context.Metadata.ModelType));
        }

        return null;
    }
}

पंजीकरण समारोह:

    public static void AddStringTrimmingProvider(this MvcOptions option)
    {
        var binderToFind = option.ModelBinderProviders
            .FirstOrDefault(x => x.GetType() == typeof(SimpleTypeModelBinderProvider));

        if (binderToFind == null)
        {
            return;
        }

        var index = option.ModelBinderProviders.IndexOf(binderToFind);
        option.ModelBinderProviders.Insert(index, new TrimmingModelBinderProvider());
    }

रजिस्टर करें:

service.AddMvc(option => option.AddStringTrimmingProvider())

+1। ठीक वही जो मेरे द्वारा खोजा जा रहा था। पंजीकरण समारोह में "binderToFind" कोड का उद्देश्य क्या है?
ब्रैड

मैं सिर्फ SimpleTypeModelBinderProviderएक ही इंडेक्स को बनाए रखने के साथ कस्टम प्रदाता को वापस लाने की कोशिश कर रहा हूं ।
विकाश कुमार

संपूर्ण विवरण यहाँ पाया जा सकता है vikutech.blogspot.in/2018/02/…
विकाश कुमार

3

पार्टी के लिए देर से, लेकिन निम्नलिखित एमवीसी 5.2.3 के लिए आवश्यक समायोजन का एक सारांश है यदि आप skipValidationबिल्ड-इन मूल्य प्रदाताओं की आवश्यकता को संभालना चाहते हैं ।

public class TrimStringModelBinder : IModelBinder
{
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        // First check if request validation is required
        var shouldPerformRequestValidation = controllerContext.Controller.ValidateRequest && 
            bindingContext.ModelMetadata.RequestValidationEnabled;

        // determine if the value provider is IUnvalidatedValueProvider, if it is, pass in the 
        // flag to perform request validation (e.g. [AllowHtml] is set on the property)
        var unvalidatedProvider = bindingContext.ValueProvider as IUnvalidatedValueProvider;

        var valueProviderResult = unvalidatedProvider?.GetValue(bindingContext.ModelName, !shouldPerformRequestValidation) ??
            bindingContext.ValueProvider.GetValue(bindingContext.ModelName);

        return valueProviderResult?.AttemptedValue?.Trim();
    }
}

Global.asax

    protected void Application_Start()
    {
        ...
        ModelBinders.Binders.Add(typeof(string), new TrimStringModelBinder());
        ...
    }

2

मैं समाधान से असहमत हूं। आपको GetPropertyValue को ओवरराइड करना चाहिए क्योंकि SetProperty का डेटा भी ModelState द्वारा भरा जा सकता है। इनपुट तत्वों से कच्चे डेटा को पकड़ने के लिए इसे लिखें:

 public class CustomModelBinder : System.Web.Mvc.DefaultModelBinder
{
    protected override object GetPropertyValue(System.Web.Mvc.ControllerContext controllerContext, System.Web.Mvc.ModelBindingContext bindingContext, System.ComponentModel.PropertyDescriptor propertyDescriptor, System.Web.Mvc.IModelBinder propertyBinder)
    {
        object value = base.GetPropertyValue(controllerContext, bindingContext, propertyDescriptor, propertyBinder);

        string retval = value as string;

        return string.IsNullOrWhiteSpace(retval)
                   ? value
                   : retval.Trim();
    }

}

प्रॉपर्टीस्क्रिप्ट फ़िल्टर करें प्रॉपटाइप यदि आप वास्तव में केवल स्ट्रिंग मानों में रुचि रखते हैं, लेकिन इससे कोई फर्क नहीं पड़ना चाहिए क्योंकि जो कुछ भी आता है वह मूल रूप से एक स्ट्रिंग है।


2

के लिए ASP.NET कोर , की जगह ComplexTypeModelBinderProviderएक प्रदाता है कि तार ट्रिम के साथ।

अपने स्टार्टअप कोड ConfigureServicesविधि में, इसे जोड़ें:

services.AddMvc()
    .AddMvcOptions(s => {
        s.ModelBinderProviders[s.ModelBinderProviders.TakeWhile(p => !(p is ComplexTypeModelBinderProvider)).Count()] = new TrimmingModelBinderProvider();
    })

TrimmingModelBinderProviderइस तरह परिभाषित करें:

/// <summary>
/// Used in place of <see cref="ComplexTypeModelBinderProvider"/> to trim beginning and ending whitespace from user input.
/// </summary>
class TrimmingModelBinderProvider : IModelBinderProvider
{
    class TrimmingModelBinder : ComplexTypeModelBinder
    {
        public TrimmingModelBinder(IDictionary<ModelMetadata, IModelBinder> propertyBinders) : base(propertyBinders) { }

        protected override void SetProperty(ModelBindingContext bindingContext, string modelName, ModelMetadata propertyMetadata, ModelBindingResult result)
        {
            var value = result.Model as string;
            if (value != null)
                result = ModelBindingResult.Success(value.Trim());
            base.SetProperty(bindingContext, modelName, propertyMetadata, result);
        }
    }

    public IModelBinder GetBinder(ModelBinderProviderContext context)
    {
        if (context.Metadata.IsComplexType && !context.Metadata.IsCollectionType) {
            var propertyBinders = new Dictionary<ModelMetadata, IModelBinder>();
            for (var i = 0; i < context.Metadata.Properties.Count; i++) {
                var property = context.Metadata.Properties[i];
                propertyBinders.Add(property, context.CreateBinder(property));
            }
            return new TrimmingModelBinder(propertyBinders);
        }
        return null;
    }
}

इसका बदसूरत हिस्सा GetBinderतर्क की कॉपी और पेस्ट है ComplexTypeModelBinderProvider, लेकिन आपको इससे बचने के लिए कोई हुक नहीं लगता है।


मुझे पता नहीं क्यों, लेकिन यह ASP.NET Core 1.1.1 के लिए काम नहीं करता है। नियंत्रक क्रिया में मुझे प्राप्त मॉडल ऑब्जेक्ट के सभी गुण शून्य हैं। "सेटप्रॉपर्टी" विधि nerver कहलाती है।
वाल्डो

मेरे लिए काम नहीं किया, मेरी संपत्ति की शुरुआत में जगह अभी भी है।
सेड्रिक अर्नोल्ड

2

मैंने क्वेरी स्ट्रिंग पैरामीटर मानों और प्रपत्र मानों को ट्रिम करने के लिए मूल्य प्रदाता बनाए। यह ASP.NET Core 3 के साथ परीक्षण किया गया था और पूरी तरह से काम करता है।

public class TrimmedFormValueProvider
    : FormValueProvider
{
    public TrimmedFormValueProvider(IFormCollection values)
        : base(BindingSource.Form, values, CultureInfo.InvariantCulture)
    { }

    public override ValueProviderResult GetValue(string key)
    {
        ValueProviderResult baseResult = base.GetValue(key);
        string[] trimmedValues = baseResult.Values.Select(v => v?.Trim()).ToArray();
        return new ValueProviderResult(new StringValues(trimmedValues));
    }
}

public class TrimmedQueryStringValueProvider
    : QueryStringValueProvider
{
    public TrimmedQueryStringValueProvider(IQueryCollection values)
        : base(BindingSource.Query, values, CultureInfo.InvariantCulture)
    { }

    public override ValueProviderResult GetValue(string key)
    {
        ValueProviderResult baseResult = base.GetValue(key);
        string[] trimmedValues = baseResult.Values.Select(v => v?.Trim()).ToArray();
        return new ValueProviderResult(new StringValues(trimmedValues));
    }
}

public class TrimmedFormValueProviderFactory
    : IValueProviderFactory
{
    public Task CreateValueProviderAsync(ValueProviderFactoryContext context)
    {
        if (context.ActionContext.HttpContext.Request.HasFormContentType)
            context.ValueProviders.Add(new TrimmedFormValueProvider(context.ActionContext.HttpContext.Request.Form));
        return Task.CompletedTask;
    }
}

public class TrimmedQueryStringValueProviderFactory
    : IValueProviderFactory
{
    public Task CreateValueProviderAsync(ValueProviderFactoryContext context)
    {
        context.ValueProviders.Add(new TrimmedQueryStringValueProvider(context.ActionContext.HttpContext.Request.Query));
        return Task.CompletedTask;
    }
}

फिर ConfigureServices()Startup.cs में फ़ंक्शन में मूल्य प्रदाता कारखानों को पंजीकृत करें

services.AddControllersWithViews(options =>
{
    int formValueProviderFactoryIndex = options.ValueProviderFactories.IndexOf(options.ValueProviderFactories.OfType<FormValueProviderFactory>().Single());
    options.ValueProviderFactories[formValueProviderFactoryIndex] = new TrimmedFormValueProviderFactory();

    int queryStringValueProviderFactoryIndex = options.ValueProviderFactories.IndexOf(options.ValueProviderFactories.OfType<QueryStringValueProviderFactory>().Single());
    options.ValueProviderFactories[queryStringValueProviderFactoryIndex] = new TrimmedQueryStringValueProviderFactory();
});

0

एक विशेषता दृष्टिकोण का सुझाव देने वाले बहुत सारे पद हैं। यहां एक पैकेज है जिसमें पहले से ही ट्रिम विशेषता है और कई अन्य हैं: Dado.ComponentModel.Mutations या NuGet

public partial class ApplicationUser
{
    [Trim, ToLower]
    public virtual string UserName { get; set; }
}

// Then to preform mutation
var user = new ApplicationUser() {
    UserName = "   M@X_speed.01! "
}

new MutationContext<ApplicationUser>(user).Mutate();

Mutate () पर कॉल करने के बाद user.UserName को म्यूट कर दिया जाएगा m@x_speed.01!

यह उदाहरण व्हॉट्सएप को ट्रिम कर देगा और स्ट्रिंग को लोअरकेस में भेज देगा। यह सत्यापन का परिचय नहीं देता है, लेकिन System.ComponentModel.Annotationsइसका उपयोग किया जा सकता है Dado.ComponentModel.Mutations


0

मैंने इसे दूसरे धागे में पोस्ट किया है। Asp.net कोर 2 में, मैं एक अलग दिशा में चला गया। मैंने इसके बजाय एक्शन फिल्टर का इस्तेमाल किया। इस मामले में, डेवलपर या तो इसे विश्व स्तर पर सेट कर सकता है या उन कार्यों के लिए एक विशेषता के रूप में उपयोग कर सकता है जो वह स्ट्रिंग ट्रिमिंग लागू करना चाहता है। यह कोड मॉडल बाध्यकारी होने के बाद चलता है, और यह मॉडल ऑब्जेक्ट में मानों को अपडेट कर सकता है।

यहां मेरा कोड है, पहले एक एक्शन फ़िल्टर बनाएं:

public class TrimInputStringsAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext context)
    {
        foreach (var arg in context.ActionArguments)
        {
            if (arg.Value is string)
            {
                string val = arg.Value as string;
                if (!string.IsNullOrEmpty(val))
                {
                    context.ActionArguments[arg.Key] = val.Trim();
                }

                continue;
            }

            Type argType = arg.Value.GetType();
            if (!argType.IsClass)
            {
                continue;
            }

            TrimAllStringsInObject(arg.Value, argType);
        }
    }

    private void TrimAllStringsInObject(object arg, Type argType)
    {
        var stringProperties = argType.GetProperties()
                                      .Where(p => p.PropertyType == typeof(string));

        foreach (var stringProperty in stringProperties)
        {
            string currentValue = stringProperty.GetValue(arg, null) as string;
            if (!string.IsNullOrEmpty(currentValue))
            {
                stringProperty.SetValue(arg, currentValue.Trim(), null);
            }
        }
    }
}

इसका उपयोग करने के लिए, या तो वैश्विक फ़िल्टर के रूप में पंजीकरण करें या ट्रिमइन्पुटस्ट्रीम विशेषता के साथ अपने कार्यों को सजाएं।

[TrimInputStrings]
public IActionResult Register(RegisterViewModel registerModel)
{
    // Some business logic...
    return Ok();
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.