gpt4 book ai didi

asp.net-mvc - 使用自定义 ASP.NET MVC IValueProvider,而不进行全局设置?

转载 作者:行者123 更新时间:2023-12-04 00:53:14 26 4
gpt4 key购买 nike

我希望能够从 cookie 中获取键/值并使用它来绑定(bind)模型。

我相信 DefaultModelBinder 开箱即用,而不是构建自定义 ModelBinder,并且选择值来自何处的最佳方法是设置它使用的 IValueProvider。

为此,我不想创建自定义 ValueProviderFactory 并将其绑定(bind)到全局,因为我只希望此 ValueProvider 用于特定的操作方法。

我已经建立了一个执行此操作的属性:

/// <summary>
/// Replaces the current value provider with the specified value provider
/// </summary>
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMultiple = true)]
public class SetValueProviderAttribute : ActionFilterAttribute
{
public SetValueProviderAttribute(Type valueProviderType)
{
if (valueProviderType.GetInterface(typeof(IValueProvider).Name) == null)
throw new ArgumentException("Type " + valueProviderType + " must implement interface IValueProvider.", "valueProviderType");

_ValueProviderType = valueProviderType;
}

private Type _ValueProviderType;

public override void OnActionExecuting(ActionExecutingContext filterContext)
{
IValueProvider valueProviderToAdd = GetValueProviderToAdd();

filterContext.Controller.ValueProvider = valueProviderToAdd;
}

private IValueProvider GetValueProviderToAdd()
{
return (IValueProvider)Activator.CreateInstance(_ValueProviderType);
}
}

不幸的是,ModelBinder 及其 IValueProvider 是在 OnActionExecuting 之前设置的(为什么??????)。有没有其他人想出一种在不使用 ValueProviderFactory 的情况下将自定义 IValueProvider 注入(inject) DefaultModelBinder 的方法?

最佳答案

这是一种替代方法,可让您将 IValueProviders 指定为针对操作参数的属性。
这使得 IValueProviders 是 transient 的,而不是全局的。

public interface IControllerContextAware
{
ControllerContext ControllerContext { get; set; }
}

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Interface | AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
public class ValueProviderAttribute : CustomModelBinderAttribute
{
public Type[] ValueProviders { get; private set; }

public ValueProviderAttribute(params Type[] valueProviders)
{
if (valueProviders == null)
{
throw new ArgumentNullException("valueProviders");
}
foreach (var valueProvider in valueProviders.Where(valueProvider => !typeof(IValueProvider).IsAssignableFrom(valueProvider)))
{
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "The valueProvider {0} must be of type {1}", valueProvider.FullName, typeof(IValueProvider)), "valueProviders");
}

ValueProviders = valueProviders;
}

public override IModelBinder GetBinder()
{
return new ValueProviderModelBinder
{
ValueProviderTypes = ValueProviders.ToList(),
CreateValueProvider = OnCreateValueProvider
};
}

protected virtual IValueProvider OnCreateValueProvider(Type valueProviderType, ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var valueProvider = (IValueProvider)Activator.CreateInstance(valueProviderType);
if (valueProvider is IControllerContextAware)
{
(valueProvider as IControllerContextAware).ControllerContext = controllerContext;
}
return valueProvider;
}

private class ValueProviderModelBinder : DefaultModelBinder
{
public IList<Type> ValueProviderTypes { get; set; }
public Func<Type, ControllerContext, ModelBindingContext, IValueProvider> CreateValueProvider { get; set; }

public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var valueProviders = from type in ValueProviderTypes
select CreateValueProvider(type, controllerContext, bindingContext);

bindingContext.ValueProvider = new ValueProviderCollection(valueProviders.Concat((Collection<IValueProvider>)bindingContext.ValueProvider).ToList());

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

这基本上是 ModelBinderAttribute 的代码,但有一些调整。
它不是密封的,因此您可以根据需要更改创建 IValueProvider 的方式。

这是一个简单的示例,它查看另一个字段,可能是隐藏或加密的字段,然后获取数据并将其放入另一个属性中。

这是模型,它不知道 IValueProvider,但知道隐藏字段。
public class SomeModel
{
[Required]
public string MyString { get; set; }

[Required]
public string MyOtherString { get; set; }

[Required]
public string Data { get; set; }
}

然后我们有 IValueProvider,在这种情况下,我的提供者明确知道我的模型,但不一定是这种情况。
public class MyValueProvider : IValueProvider, IControllerContextAware
{
public ControllerContext ControllerContext { get; set; }

public bool ContainsPrefix(string prefix)
{
var containsPrefix = prefix == "MyString" && ControllerContext.HttpContext.Request.Params.AllKeys.Any(key => key == "Data");
return containsPrefix;
}

public ValueProviderResult GetValue(string key)
{
if (key == "MyString")
{
var data = ControllerContext.RequestContext.HttpContext.Request.Params["Data"];

var myString = data.Split(':')[1];

return new ValueProviderResult(myString, myString, CultureInfo.CurrentCulture);
}
return null;
}
}

然后是把这一切联系在一起的 Action :
    [HttpGet]
public ActionResult Test()
{
return View(new SomeModel());
}

[HttpPost]
public ActionResult Test([ValueProvider(typeof(MyValueProvider))]SomeModel model)
{
return View(model);
}

关于asp.net-mvc - 使用自定义 ASP.NET MVC IValueProvider,而不进行全局设置?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7600212/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com