首页 > 解决方案 > UnitsNet - 如何在 MVC 中使用它?

问题描述

如何在 MVC Web 应用程序中使用 UnitsNet nuget 包?

例如我有我的对象:

public class UnitsNetTestViewModel
{
    public int AnInput { get; set; }
    public UnitsNet.Temperature OutdoorTemperature { get; set; }
}

然后我的看法

@model WebApplication.Models.UnitsNetTestViewModel
@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()

    @Html.LabelFor(model => model.AnInput)
    @Html.EditorFor(model => model.AnInput)
    <br/>

    @Html.LabelFor(model => model.OutdoorTemperature)
    @Html.EditorFor(model => model.OutdoorTemperature)
    <button type="submit">Submit</button>
}

在我的控制器中

    public class UnitsNetTestController : Controller
{
    // GET: UnitNetsTest
    public ActionResult Index()
    {
        var model = new Models.UnitsNetTestViewModel {OutdoorTemperature = Temperature.FromDegreesFahrenheit(80)};
        return View("~/Views/UnitsNetTest.cshtml", model);
    }

    [HttpPost]
    public ActionResult Index(Models.UnitsNetTestViewModel model)
    {
        if (ModelState.IsValid)
        {
            return View("~/Views/Home/Index.cshtml");
        }
        return View("~/Views/UnitsNetTest.cshtml", model);
    }
}

我试过使用EditorForor TextBoxFor。我还尝试在对象的不同部分进行绑定:

model => model.OutdoorTemperature.Value
model => model.OutdoorTemperature.DegreesFahrenheit
model => model.OutdoorTemperature

即使在使用EditorFor model.OutdoorTemperature组合时,我也会得到完整的对象输入字段,当我更新一个值时,它总是在控制器提交中返回为零。

我究竟做错了什么 ?

谢谢。

编辑 1

为了了解 UnitsNet 属性是如何工作的,我在模型中添加了一个子类,以查看我的子类值是否可以在控制器中使用(即使我已经知道它会起作用)。我从中注意到:在手表中,我的model.Other财产的价值是{...WebApplication.Models.SubClass},类型也是...WebApplication.Models.SubClass。但是对于model.OutdoorTemperature,值是{0 K},类型是UnitsNet.Temperature。这可能是一个线索吗?

这是一个打印屏幕: 调试手表打印屏幕

更新类:

public class UnitsNetTestViewModel
{
    public int AnInput { get; set; }
    public UnitsNet.Temperature OutdoorTemperature { get; set; }
    public SubClass Other { get; set; }
}

public class SubClass
{
    public int Value { get; set; }
    public int MySubClassValue { get; set; }
}

更新视图:

@model WebApplication.Models.UnitsNetTestViewModel
@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()

    @Html.LabelFor(model => model.AnInput)
    @Html.EditorFor(model => model.AnInput)
    <br />

    @Html.LabelFor(model => model.OutdoorTemperature)
    @Html.TextBoxFor(model => model.OutdoorTemperature.Value)

    <br />
    @Html.LabelFor(model => model.Other)
    @Html.TextBoxFor(model => model.Other.Value)

    <br />
    @Html.LabelFor(model => model.Other)
    @Html.TextBoxFor(model => model.Other.MySubClassValue)


    <button type="submit">Submit</button>
}

编辑 2

UnitsNet.Temperature是一个结构,而不是一个类。可能需要一个自定义模型绑定器。

标签: c#model-view-controller

解决方案


最后,MVC 的默认绑定不起作用,因为 UnitsNet 是结构。

我做了一个自定义属性活页夹。

我用这篇文章作为参考: http: //www.stevencwilliams.com/2015/10/26/custom-property-binding-in-asp-net-mvc/

这是使我的示例工作的代码:

public class TemperatureModelBinder : IPropertyBinder
{
    public object BindProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor)
    {            
        var propertyValue = controllerContext.HttpContext.Request.Form[propertyDescriptor.Name];
        double.TryParse(propertyValue, out var result);

        return UnitsNet.Temperature.FromDegreesFahrenheit(result);
    }
}

public interface IPropertyBinder
{
    object BindProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor);
}

[AttributeUsage(AttributeTargets.Property)]
public class PropertyBinderAttribute : Attribute
{
    public Type BinderType { get; private set; }

    public PropertyBinderAttribute(Type binderType)
    {
        BinderType = binderType;
    }

    public IPropertyBinder GetBinder()
    {
        return (IPropertyBinder)DependencyResolver.Current.GetService(BinderType);
    }
}

public class ModelBinderBase : DefaultModelBinder
{
    protected override void BindProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor)
    {
        PropertyBinderAttribute attribute = propertyDescriptor.Attributes
            .OfType<PropertyBinderAttribute>()
            .SingleOrDefault();
        if (attribute == null)
        {
            base.BindProperty(controllerContext, bindingContext, propertyDescriptor);
        }
        else
        {
            propertyDescriptor.SetValue(bindingContext.Model, attribute.GetBinder().BindProperty(controllerContext, bindingContext, propertyDescriptor));
        }
    }
}

在我的模型中,我添加了我的 binder 属性

    [PropertyBinder(typeof(TemperatureModelBinder))]
    public UnitsNet.Temperature OutdoorTemperature { get; set; }

在 Global.asax.cs 中,Application_Start()

ModelBinders.Binders.DefaultBinder = new ModelBinderBase();

推荐阅读