假设:
request.UrlReferrer.LocalPath = "/MyApp/MyHome/List";
我有一个路由映射处理这个,其中MyHome是我的控制器,List是一个采用ViewModel的动作。此路由的其他变体包括分页和排序,但这些变量由ViewModel捕获。
我的问题是:
如何使用上述URL生成相关ViewModel的实例?
编辑:我有一个JQuery对话框,它添加/更新/删除列表中的项目,该列表由urlreferrer中的url显示 - 给出的示例是最基本的。当对话框将数据发送为/ u / d时,我想返回列表的更新主体并显示它。此信息由与对话框中POST实例化的不同ViewModel处理(发布到的URL是“/ MyApp / MyHome / Edit / True” - 用于创建新的任何内容)。这篇文章遵循标准的MVC流程,当然也可以。我想要做的是基于列表操作的ViewModel创建第二 ViewModel,并将其作为包含更新的分页列表的部分视图返回。
答案 0 :(得分:0)
好的......我想我已经搞清楚了。这不是很漂亮,但它确实有效。我欢迎任何人的输入通过ModelBinder或任何其他MVC工件实际提供这个,但这是我想出的:
首先,我们需要使用UrlReferrer而不是请求的实际网址伪造请求:
public class FakeHttpContext : HttpContextBase
{
public FakeHttpContext(HttpContextBase currentContext)
{
_request = new FakeHttpRequest(currentContext.Request);
}
HttpRequestBase _request;
public override HttpRequestBase Request
{
get
{
return _request;
}
}
HttpResponseBase _response = new FakeHttpResponse();
public override HttpResponseBase Response
{
get
{
return _response;
}
}
class FakeHttpRequest : HttpRequestBase
{
HttpRequestBase _request;
public FakeHttpRequest(HttpRequestBase currentRequest)
{
if(currentRequest == null)
throw new ArgumentNullException();
this._request = currentRequest;
}
public override string ApplicationPath
{
get
{
return this._request.ApplicationPath;
}
}
public override string AppRelativeCurrentExecutionFilePath
{
get
{
return "~" + this._request.UrlReferrer.AbsolutePath.Remove(0, this._request.ApplicationPath.Length);
}
}
public override string PathInfo
{
get
{
return this._request.PathInfo;
}
}
}
class FakeHttpResponse : HttpResponseBase
{
}
}
接下来,我们通过RouteTable提供虚假来电,以便将其分解。并将属性与RouteData.Values匹配。
public static class RouteAndModelBinder
{
public static void BuildViewModel<TViewModel>(ControllerContext context, TViewModel model)
{
FakeHttpContext fake = new FakeHttpContext(context.HttpContext);
RouteData test = RouteTable.Routes.GetRouteData(fake);
PropertyInfo[] properties = typeof(TViewModel).GetProperties();
string value;
foreach(PropertyInfo info in properties)
{
if(test.Values.ContainsKey(info.Name))
{
value = (string)test.Values[info.Name];
if(value == null)
{
continue;
}
if(info.PropertyType.IsGenericType &&
info.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
{
Type[] nullables = info.PropertyType.GetGenericArguments();
if(nullables.Length > 0)
{
Type nullableType = nullables[0];
if(nullableType.BaseType == typeof(Enum))
{
object o = Enum.Parse(nullableType, value);
info.SetValue(model, o, null);
}
else if(nullableType == typeof(Int32))
{
info.SetValue(model, int.Parse(value), null);
}
else
{
info.SetValue(model, Convert.ChangeType(value, info.PropertyType), null);
}
}
}
else
{
if(info.PropertyType.BaseType == typeof(Enum))
{
object o = Enum.Parse(info.PropertyType.BaseType, value);
info.SetValue(model, o, null);
}
else if(info.PropertyType == typeof(Int32))
{
info.SetValue(model, int.Parse(value), null);
}
else
{
info.SetValue(model, value, null);
}
}
}
}
}
}
同样,我欢迎任何人就如何使用已经建立的MVC代码(即ModelBinders等)执行此操作的建议。我从here (可空类型)和here中获取了一些想法和代码。