Получаване на стойността на List‹T› в персонализиран IValueProvider ASP.NET MVC 5.2.3

След като се борих с този проблем почти 2 дни, реших да дойда тук и да задам този въпрос - ще направя всичко възможно да бъда възможно най-ясен.

На първо място, това, което се опитвам да направя, е доста просто: внедряване на персонализиран IValueProvider, който декриптира параметрите на действие вътре в ASP.NET MVC контролер - тази част е готова и работи перфектно; проблемът ми започва в момента, в който имам списък сред параметрите за действие, защото не мога да изчисля точно стойностите на този списък от контекста на заявката.

Нека го направим стъпка по стъпка.

Първо, имам атрибут, който украсява необходимите действия:

public class EncryptedQueryStringValuesAttribute : FilterAttribute, IAuthorizationFilter
{
    /// <summary>
    /// Called when authorization is required.
    /// </summary>
    /// <param name="filterContext">The filter context.</param>
    public void OnAuthorization(AuthorizationContext filterContext)
    {
        filterContext.Controller.ValueProvider = new EncryptedQueryStringValuesProvider(
            filterContext.RequestContext, filterContext.ActionDescriptor);
    }
}

След това имам конструктора на доставчик на стойност, където инициализирам това, от което се нуждая:

public EncryptedQueryStringValuesProvider(RequestContext requestContext, ActionDescriptor actionDescriptor)
{
    this.requestContext = requestContext;
    this.actionDescriptor = actionDescriptor;

    this.prefixContainer =
        new Lazy<PrefixContainer>(
            () => new PrefixContainer(this.requestContext.HttpContext.Request.Params.AllKeys), true);
}

Като странична бележка, prefixContainer наистина работи като чар - ако проверявам дали има префикс в контейнера, той работи перфектно, независимо от типа на префикса (което означава, че няма значение дали параметърът е колекция или прост параметър).

Проверката на съществуването на параметър в доставчика на стойност се извършва по следния начин:

public bool ContainsPrefix(string prefix)
{
    return this.prefixContainer.Value.ContainsPrefix(prefix);
}

Както казах - това ми дава правилни стойности.

Сега идва грозната част - методът GetValue:

public ValueProviderResult GetValue(string key)
{
    string[] rawValue = this.requestContext.HttpContext.Request.Params.GetValues(key);
    string attemptedValue = this.requestContext.HttpContext.Request.Params[key];
    return new ValueProviderResult(rawValue, attemptedValue, CultureInfo.CurrentCulture);
}

rawValue as е извлечен в момента е null и е логично да е null, защото няма ключ с това име в моята заявка - всичко, което имам там, е просто колекция като тази:

[25]: "SupplierInvoices[x].PaymentToInvoiceExchangeRate"
[26]: "SupplierInvoices[x].AmountToPayOnGivenInvoice"
[27]: "SupplierInvoices[x].OpenInvoiceId"
[28]: "SupplierInvoices[x].OpenInvoiceTimestamp"

От друга страна, аз съм напълно наясно, че трябва да използвам конструкцията this.prefixContainer.Value.GetKeysFromPrefix(prefix);, за да получа всички ключове, които са в моята заявка и въз основа на това по някакъв начин да съединя тези ключове и да ги върна обратно към ValueProviderResult, НО НЯМАМ ИДЕЯ КАК! :-)

Моля, има някой, който може да обясни как тези стойности могат да бъдат обединени, за да бъдат върнати обратно към ValueProviderResult, за да бъдат правилно интерпретирани?

БЛАГОДАРЯ ТИ!


person Edi    schedule 06.04.2016    source източник


Отговори (1)


След като се борих с този проблем през последните седмици, реших, че трябва да променя подхода и да се опитам да не изобретявам отново колелото. Първо, трябва да изпусна всичко, което имам, свързано с обработката на колекцията и всички тези неща - така че всичко, което е за this.prefixContainer, трябва да отиде - ако не мога да намеря простия ключ в HTTPContext, не трябва да го обработвам и да го оставя на останалите доставчици.

Тук идва друг проблем - как мога да "кажа" на моя доставчик на стойност да "пусне" за ключ??? Първоначално си помислих, че ако върна false в метода ContainsPrefix, обработката ще превключи към следващия IValueProvider в опашката - това не е така - и методът ContainsPrefix трябва да върне null и повече от това, методът GetValue трябва да върне null и само при тези обстоятелства обработката ще премине към следващия IValueProvider.

ОК - сега, когато имам всички тези неща на място, как мога да използвам моя доставчик на стойност без ValueProviderFactory регистриран глобално, защото, както казах, обработката се извършва само за действието, "подписано" с даден атрибут. Отговорът е следният - вместо да създавате персонализирания ValueProvider в Controller, като използвате кода на атрибута по следния начин:

filterContext.Controller.ValueProvider = new EncryptedQueryStringValuesProvider(filterContext.RequestContext, filterContext.ActionDescriptor);

Трябва да добавя своя доставчик на стойност в горната част на списъка:

ValueProviderCollection valueProviderCollection = filterContext.Controller.ValueProvider as ValueProviderCollection;
if (valueProviderCollection == null)
throw new NullReferenceException("filterContext.Controller.ValueProvider as ValueProviderCollection");

valueProviderCollection.Insert(0, new EncryptedQueryStringValuesProvider(filterContext.RequestContext, filterContext.ActionDescriptor));

Надявам се, че това ще помогне на някого. :-)

person Edi    schedule 19.04.2016