ASP.NET MVC4通用字段初始化
在ASP.NET MVC4中,我想用值初始化字段。当用户获得页面时,在他发回页面之前,我想让它以一些字段中的值开始。这些值将从查询字符串中提取,而不是硬编码。假设用户正在填写表单:他已登录,您知道他的姓名和地址。出于礼貌,将这些设置为默认值。实际上,它们来自哪里并不重要,只是它是一组键值对,值是字符串。我只想在字段中放置一些内容,而不让用户先发布表单,我真的希望这样做,而不需要在一个相当复杂的模型中为每个属性硬编码一个长长的赋值列表 现在它是在ASP.NET MVC4通用字段初始化,asp.net,asp.net-mvc,asp.net-mvc-4,query-string,request.querystring,Asp.net,Asp.net Mvc,Asp.net Mvc 4,Query String,Request.querystring,在ASP.NET MVC4中,我想用值初始化字段。当用户获得页面时,在他发回页面之前,我想让它以一些字段中的值开始。这些值将从查询字符串中提取,而不是硬编码。假设用户正在填写表单:他已登录,您知道他的姓名和地址。出于礼貌,将这些设置为默认值。实际上,它们来自哪里并不重要,只是它是一组键值对,值是字符串。我只想在字段中放置一些内容,而不让用户先发布表单,我真的希望这样做,而不需要在一个相当复杂的模型中为每个属性硬编码一个长长的赋值列表 现在它是在$(document).ready()中的JS循环中
$(document).ready()中的JS循环中完成的,但它属于服务器。不过,我想复制这种逻辑:将查询参数名称视为唯一标识符
在控制器的Index()
方法中,我尝试调用ModelState.TrySetModelValue()
(当填充ModelState
时,它用一个唯一的字符串标识每个字段),但在这个阶段,ModelState
是空的,因此当然这不起作用。我尝试更改Index()以期望模型的实例作为参数,但这没有帮助
我必须重写应用程序中的每个@Html.EditorFor()
/TextBoxFor()
/等调用吗?这似乎很疯狂。正确地说,这是一个循环,在一个地方,而不是分散在越来越多的视图中的多个点上
我有一种感觉,我没有掌握MVC4工作方式的一些基本原理
更新2
事实证明,如果您使用[HttpGet]
来修饰您的操作方法,并且您希望将模型作为参数,那么如果您在查询字符串中使用字段名(foo.bar
)而不是id(foo\u bar
),它会自动执行我想要的操作<代码>模型状态
已填充。当我查看ModelState
时,我一定没有用[HttpGet]
修饰动作方法
如果字段是通过查询字符串自动设置的,则该字段将取代模型中的任何字段。这是合理的;关键是覆盖模型的默认值。但是,如果您想反过来覆盖可能的查询字符串值(例如,假设“电子签名”有一个复选框;这应该总是需要用户做出明确的努力),那么您必须通过ModelState
来完成
这意味着我下面的第一个解决方案没有实际效果(前提是我在action方法上有[HttpGet]
属性)。它只设置框架已在ModelState
中设置的模型属性,因此忽略模型中的值
有点奇怪的是,ModelState
为字段提供了一个不同的键,如果它们不在查询字符串中foo.bar.baz
如果它在查询字符串中,则仅将其用作键,如果它不在查询字符串中,则该键变为foo.footypename.bar.bartypename.baz
。如果属性的名称与其类型相同,则会出现异常:我有一个名称
模型类,另一个模型类有一个属性公共名称{get;set}
。名为Name的Name
类型的属性在ModelState
键中永远不会后跟其类型名称。但是,我还没有排除排除排除该特定属性的类型名的其他可能原因。那是猜测。在我的模型中的所有情况下,“叶”属性的类型名都被排除在外。这是因为它们是系统已知的类型,还是“叶子”,还是什么?我不知道
在任何情况下,模型的“root”类的叶属性总是使用自己的名称作为ModelState
中的键
因此,广义的答案是你分配给模型。但是对于初始化,有一个与查询字符串不同的特定答案
更新
解决方案——大量代码被截断
// Controller base
public abstract class ControllerBase<TModel> : Controller
{
[HttpGet]
public virtual ActionResult Index(TModel model)
{
HttpContext.Request.QueryString.CopyTo(model);
return View("Index", model);
}
}
public static class Extensions
{
/// <summary>
/// Given NameValueCollection of keys/values in the form
/// "foo.bar.baz" = "text", and an object which is the *parent* of
/// foo, set properties of foo accordingly.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="src"></param>
/// <param name="model"></param>
public static void CopyTo<T>(this NameValueCollection src, T target)
{
String strkey;
Object objval;
foreach (var key in src.Keys)
{
strkey = "" + key;
objval = src[strkey];
target.TrySetPropertyValue(strkey, objval);
}
}
/// <summary>
/// Given a reference to an object objThis, the string "foo.bar.baz",
/// and an object o of a type optimistically hoped to be convertible
/// to that of objThis.foo.bar.baz, set objThis.foo.bar.baz = o
///
/// If foo.bar is null, it must have a default constructor, or we fail
/// and return false.
/// </summary>
/// <param name="objThis"></param>
/// <param name="propPathName"></param>
/// <param name="value"></param>
/// <returns></returns>
public static bool TrySetPropertyValue(this object objThis,
string propPathName, object value)
{
if (string.IsNullOrWhiteSpace(propPathName))
{
throw new ArgumentNullException(propPathName);
}
var names = propPathName.Split(new char[] { '.' }).ToList();
var nextPropInfo = objThis.GetType().GetProperty(names.First());
if (null == nextPropInfo)
return false;
if (names.Count > 1)
{
var nextPropValue = nextPropInfo.GetValue(objThis, null);
if (null == nextPropValue)
{
nextPropValue = Activator
.CreateInstance(nextPropInfo.PropertyType);
nextPropInfo.SetValue(objThis, nextPropValue);
}
names.RemoveAt(0);
return nextPropValue.TrySetPropertyValue(
String.Join(".", names), value);
}
else
{
try
{
var conv = System.ComponentModel.TypeDescriptor
.GetConverter(nextPropInfo.PropertyType);
value = conv.ConvertFrom(value);
nextPropInfo.SetValue(objThis, value);
}
catch (System.FormatException)
{
return false;
}
return true;
}
}
}
//控制器基础
公共抽象类ControllerBase:Controller
{
[HttpGet]
公共虚拟操作结果索引(TModel模型)
{
HttpContext.Request.QueryString.CopyTo(模型);
返回视图(“索引”,模型);
}
}
公共静态类扩展
{
///
///给定名称值表单中键/值的集合
///“foo.bar.baz”=“text”,以及作为
///foo,相应地设置foo的属性。
///
///
///
///
公共静态void CopyTo(此NameValueCollection src,T目标)
{
弦斯特基;
对象对象对象;
foreach(src.Keys中的var键)
{
strkey=“”+键;
objval=src[strkey];
target.TrySetPropertyValue(strkey,objval);
}
}
///
///给定对对象对象的引用,字符串“foo.bar.baz”,
///以及一个乐观地希望可以转换的对象
///将objThis.foo.bar.baz设置为objThis.foo.bar.baz=o
///
///如果foo.bar为null,则它必须具有默认构造函数,否则我们将失败
///返回false。
///
///
///
///
///
公共静态bool TrySetPropertyValue(此对象对象),
字符串propPathName,对象值)
{
if(string.IsNullOrWhiteSpace(propPathName))
{
抛出新ArgumentNullException(propPathName);
}
var names=propPathName.Split(新字符[]{.'}).ToList();
var nextPropInfo=objThis.GetType().GetProperty(names.First());
if(null==nextPropInfo)
返回false;
如果(names.Count>1)
{
var nextPropValue=nextPropInfo.GetValue(objThis,null)
@Html.TextBoxFor(m => Model.Name)
public ActionResult Index()
{
MyModel model = new MyModel();
model.Name = "myname";
return View("myview", model);
}
@Html.TextBoxFor(m => Model.Name, new { value = "myname"})
public ActionResult Edit(string id)
{ ...