使用MVC模型绑定在运行时转换数据

时间:2018-07-05 10:42:59

标签: c# .net asp.net-mvc

我制作了一个函数,该函数接受MethodBase对象和命名参数的字典,并将命名参数与方法匹配,然后转换数据,以便可以使用正确的参数调用该方法。

为了转换我一直在使用的数据

parameters[paramIndex] = Convert.ChangeType(item.Value, paramType);

但是,这不适用于MVC绑定类型,因为简单地调用MethodBase对象并不能通过MVC绑定执行数据转换。

我可以这样做来检查要转换的类型是否具有活页夹

if(ModelBinders.Binders.TryGetValue(paramType, out var binder)){...}

但是我不确定然后如何使用活页夹转换数据。我尝试使用this answer,但没有解释ModelBindingContext参数的实际含义以及如何将其用于这些目的。

上下文

提供一些上下文可能是明智的选择:我正在尝试执行此操作,因为我们执行了SVG和HTML DOM的服务器端渲染(使用Puppeteer / batik),但是有些DOM嵌入了带有链接的图像。

因此在执行渲染之前:

  • 从DOM查找图像URL
  • 解析参数并路由
  • 找到要通过其MVC路线属性调用装配的方法
  • 使用转换后的参数调用方法以渲染图像
  • 将结果转换为base64
  • 将DOM中的嵌入式图像更改为使用base64表示形式而不是URL

预先感谢您的帮助。

整个方法定义为:

    private static object[] MapParameters(MethodBase method, IDictionary<string, object> namedParameters)
    {
        var parms = method.GetParameters();
        var paramNames = parms.Select(p => p.Name).ToArray();
        var parameters = new object[paramNames.Length];
        for (var i = 0; i < parameters.Length; ++i)
            parameters[i] = Type.Missing;

        foreach (var item in namedParameters)
        {
            var param = parms.First(parm => parm.Name == item.Key);
            var paramType = Nullable.GetUnderlyingType(param.ParameterType) ?? param.ParameterType;
            var paramName = item.Key;
            var paramIndex = Array.IndexOf(paramNames, paramName);

            if (ModelBinders.Binders.TryGetValue(paramType, out var binder))
            {
                // Use the binder to convert data
                continue;
            }

            parameters[paramIndex] = Convert.ChangeType(item.Value, paramType);
        }

        return parameters;
    }

1 个答案:

答案 0 :(得分:0)

要解决此问题,您只需在IModelBinder.BindModel实现上抛出一个虚假的ControllerContext和ModelBindingContext,如下所示:

private static object ConvertDataWithModelBinder(IModelBinder binder, object value)
{
    const string modelName = "ValueToBeConverted";
    var modelContext = new ModelBindingContext { ModelName = modelName };
    var routeData = new RouteData { Values = { { modelName, value } } };
    var controllerContext = new ControllerContext { RouteData = routeData };
    return binder.BindModel(controllerContext, modelContext);
}

这假设活页夹实现查看ControllerContext.RouteData.Values对象(我检查了我们的模型活页夹,大多数情况下都这样做),但是其中一些还使用BindingContext.ValueProvider.GetValue方法来从中获取值控制器上下文。

您可能还需要添加ValueProvider的虚拟实现,其中包含一个带有上述ValueProviderResult和值的单个ModelName