JsonConverter等效于HTTP GET参数 [英] JsonConverter equivalent for HTTP GET parameter

查看:63
本文介绍了JsonConverter等效于HTTP GET参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在为HTTP POST函数编写C#Web API控制器时,我可以在参数对象的属性上使用来自Newtonsoft JSON的属性.特别是,我可以在以下属性的属性上使用 JsonConverter属性 enum类型,用于将从客户端接收的字符串表示形式转换为enum值之一(对于响应对象,则返回):

When writing C# web API controllers for HTTP POST functions, I can use attributes from Newtonsoft JSON on the properties of the parameter object. In particular, I can use a JsonConverter attribute on properties of an enum type to convert a string representation received from the client into one of the enum values (and back, for response objects):

public class MyArgumentsDTO
{
    [JsonConverter(typeof(SomeEnumConverter))]
    public SomeEnum MyValue { get; set; }
}

// in the controller:
[Route("doSomething")]
[HttpPost]
public Boolean DoSomething(MyArgumentsDTO options);

但是,对于期望具有这种enum类型参数的HTTP GET方法,我应该怎么做?

However, what should I do for HTTP GET methods that expect a parameter of such an enum type?

[Route("getSomething")]
[HttpGet]
public Boolean GetSomething(SomeEnum myValue);

是否有一个属性,可以用来修饰各个参数以指示(字符串到枚举)转换器?

(要清楚,我以枚举为例,因为我经常将此技术(通过HTTP POST)与枚举一起使用.想必,任何适用于枚举的解决方案对其他任何(可能是复杂的)数据同样适用类型.

(To be clear, I am using enums as an example because I regularly use this technique (with HTTP POST) with enums. Presumeably, any solution that works for enums would just as well work for any other (possibly complex) data types.)

当然,我可以将参数声明为string,然后自己在方法主体中进行转换.但是,这似乎不干净,我同意相关答案中的声明:

Of course, I could just declare the parameter as string and do the conversion myself, in the method body. However, that seems unclean, and I agree with a statement given in a related answer:

将所有枚举参数定义为字符串,然后在任何地方解析它们意味着您必须对每一个动作执行此操作,并且您将需要采取一种一致的方法以使所有解析错误均符合要求.

Defining all your enum parameters as strings and then parsing them everywhere means you have to do this on every single action and you will need to come up with a consistent approach such that all parsing errors conform.

不幸的是,我什至不理解该答案中提出的解决方案,因为它甚至没有涉及使用该问题中提到的TypeEnum.

Unfortunately, I do not understand the solution proposed in that answer, given that it does not even touch upon using the TypeEnum mentioned in that question.

当我需要枚举参数时,对方法使用HTTP POST而不是HTTP GET似乎也是错误的.我不认为应该基于这种内部技术来选择HTTP方法.

Using HTTP POST instead of HTTP GET for methods when I need an enum parameter seems somehow wrong, as well. I don't think the HTTP method should be chosen based upon such internal technicalities.

推荐答案

ASP.NET模型绑定器正确反序列化了枚举.尝试给defininig一些简单的枚举,例如

Enums are correctly deserialized by ASP.NET model binder. Try defininig some simple enum, e.g.

public enum Color
{
    None,
    Green,
    Red,
}

[Route("getSomething")]
[HttpGet]
public string Get(Color color)
{
    // ...
}

如果您获取/api/values/color=Green,则颜色将正确设置为Color.Green.如果您需要一些自定义值转换(例如#FF0000Color.Red),则使用自定义类型转换器(见下文)的方法将很适合您.

If you GET /api/values/color=Green, color will be correctly set to Color.Green. If you need some custom values conversion (like #FF0000 to Color.Red) approach with custom Type Converter (see below) will work for you.

ASP.NET还提供了从URL反序列化更复杂的数据类型的可能性.最简单的方法是实现自定义类型转换器.这是我前一段时间开发的应用程序中的示例.它适用于具有唯一标识符(格式为<department>:<order number>,即NY:123LA:456)的订单.该模型是

ASP.NET also provides possibility to deserialize more complex data types from the url. The easiest way is to implement custom type converter. Here is a sample from the application I have developed some time ago. It worked with the orders that have unique identifiers in format <department>:<order number>, i.e. NY:123 or LA:456. The model is

public class OrderId
{
    public string DepartmentId { get; }

    public int OrderNumber { get; }

    public OrderId(string departmentId, int orderNumber)
    {
        DepartmentId = departmentId;
        OrderNumber = orderNumber;
    }
}

并且需要通过HTTP GET方法传递此类订单ID:

And it was required to pass such order ids via HTTP GET method:

[HttpGet]
public OrderDetails GetOrderDetails(OrderId orderId)

要解决此问题并根据Url参数正确创建orderId,我们可以实现自定义类型转换器,该类型转换器将字符串值转换为OrderId的实例:

To solve this and make orderId correctly created from an Url parameter, we could implement custom Type Converter that converts string value to instance of OrderId:

public class OrderIdTypeConverter : TypeConverter
{
    private static readonly Regex OrderIdRegex = new Regex("^(.+):(\\d+)$", RegexOptions.Compiled);

    public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
    {
        return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
    }

    public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
    {
        var str = value as string;
        if (str != null)
        {
            int orderId;
            var match = OrderIdRegex.Match(str);
            if (match.Success && Int32.TryParse(match.Groups[2].Value, out orderId))
            {
                return new OrderId(match.Groups[1].Value, orderId);
            }
        }

        return base.ConvertFrom(context, culture, value);
    }
}

要将此类型转换器与OrderId类相关联,只需添加TypeConverter属性:

To associate this Type Converter with OrderId class just add the TypeConverter attribute:

[TypeConverter(typeof(OrderIdTypeConverter))]
public class OrderId

现在,如果我们获得网址/api/Orders/?orderId=NYC:123,则将使用正确填充的OrderId实例调用操作GetOrderDetails.

Now if we get Url /api/Orders/?orderId=NYC:123, action GetOrderDetails will be called with correctly filled instance of OrderId.

ASP.NET提供了另一个可扩展点,用于从URL绑定模型.它们是IModelBinderIValueProvider接口的自定义实现.检查此文章以获取更多详细信息.

ASP.NET provides another extensibility points for binding the model from the URL. They are custom implementations of IModelBinder and IValueProvider interfaces. Check this article for more details.

如果无法将类型转换器设置为不受控制的类型,则使用自定义模型绑定程序的方法应该适合您.这是IModelBinder实现的示例,用于自定义枚举值的转换:

If you can't set type converter for the type that you don't control, approach with custom model binder should work for you. Here is a sample of IModelBinder implementation for customizing conversion of enum values:

public class CustomEnumModelBinder : IModelBinder
{
    public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
    {
        if (bindingContext.ModelType != typeof(Color))
        {
            return false;
        }

        ValueProviderResult val = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
        if (val == null)
        {
            return false;
        }

        string rawValue = val.RawValue as string;
        if (rawValue == null)
        {
            bindingContext.ModelState.AddModelError(bindingContext.ModelName, "Incorrect input value type");
            return false;
        }

        //  Your logic for converting string to enum.
        if (rawValue == "FF0000")
        {
            bindingContext.Model = Color.Red;
            return true;
        }

        bindingContext.ModelState.AddModelError(bindingContext.ModelName, $"Cannot convert {rawValue} to Color");
        return false;
    }
}

[Route("getSomething")]
[HttpGet]
public string Get([ModelBinder(typeof(CustomEnumModelBinder))] Color color)
{
    // ...
}

通过做一些额外的工作,您可以实现某种通用模型联编程序,这些联编程序可以聚合您现有的Json转换器.

Wit a bit of additional work you could implement some sort of generic model binder that could aggregate your existing Json converters.

这篇关于JsonConverter等效于HTTP GET参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆