Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/asp.net/33.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# “的自定义数据类型”;HttpGet“;Asp.NETWebAPI项目中的路由_C#_Asp.net_Asp.net Web Api - Fatal编程技术网

C# “的自定义数据类型”;HttpGet“;Asp.NETWebAPI项目中的路由

C# “的自定义数据类型”;HttpGet“;Asp.NETWebAPI项目中的路由,c#,asp.net,asp.net-web-api,C#,Asp.net,Asp.net Web Api,我尝试在HttpGet路由中添加一个“customdata type”变量 我有以下代码: [HttpGet("{idObject}")] public ResponseSchema Get(ObjectId idObject) { if (idObject == null) { throw new BodyParseException(); } var user = _usersLogic.GetById(idObject); if (use

我尝试在HttpGet路由中添加一个“customdata type”变量

我有以下代码:

[HttpGet("{idObject}")]
public ResponseSchema Get(ObjectId idObject)
{
    if (idObject == null) {
        throw new BodyParseException();
    }

    var user = _usersLogic.GetById(idObject);

    if (user == null) {
        _response.Success = false;
        _response.ErrorCode = "UserDoesNotExist";
    }
    else {
        _response.Objects.Add(user);
    }

    return _response;
}
ObjectId是在using MongoDB.Bson中定义的数据类型

对于Json序列化和反序列化,我们已经有了在两侧自动转换的代码。但在Url本身中也可以这样做

我们现在正在使用此Mvc版本:

"Microsoft.AspNet.Mvc": "6.0.0-beta8"
因此,URL如下所示:

GET Users/55b795827572761a08d735ac
将其从“字符串”解析为“ObjectId”的代码是:

问题是要把那个锥虫密码放在哪里。因为我需要告诉ASP.NET它应该如何将idObject从字符串解析为ObjectId。因为URL基本上是一个字符串

对于Post或Put JSON负载,我已经找到了一个解决方案。我知道这是不一样的。但了解该场景或找到该场景的解决方案可能会有所帮助:

public class EntityBaseDocument
{
    [JsonConverter(typeof(ObjectIdConverter))]
    public ObjectId Id { get; set; }
}

// Since we have this value converter. We can use ObjectId everywhere
public class ObjectIdConverter : JsonConverter
{
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        serializer.Serialize(writer, value.ToString());
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JToken token = JToken.Load(reader);
        return new ObjectId(token.ToObject<string>());
    }

    public override bool CanConvert(Type objectType)
    {
        return typeof(ObjectId).IsAssignableFrom(objectType);
    }
}
公共类EntityBaseDocument
{
[JsonConverter(类型(ObjectdConverter))]
公共对象Id{get;set;}
}
//因为我们有这个值转换器。我们可以在任何地方使用ObjectId
公共类ObjectdConverter:JsonConverter
{
公共重写void WriteJson(JsonWriter编写器、对象值、JsonSerializer序列化器)
{
serializer.Serialize(writer,value.ToString());
}
公共重写对象ReadJson(JsonReader阅读器,类型objectType,对象existingValue,JsonSerializer序列化程序)
{
JToken令牌=JToken.Load(读卡器);
返回新的ObjectId(token.ToObject());
}
公共覆盖布尔CanConvert(类型objectType)
{
返回typeof(ObjectId).IsAssignableFrom(objectType);
}
}

这将从Uri对象绑定它:

public ResponseSchema Get([FromUri]ObjectId idObject)
所以:
?param1=something¶m2=something其他

这将从主体(例如JSon对象)绑定它

或者您也可以自己滚动:

public ResponseSchema Get([ModelBinder(typeof(MyObjectBinder))]ObjectId idObject)
模型活页夹的示例如下:

public class GeoPointModelBinder : IModelBinder
{
    // List of known locations.
    private static ConcurrentDictionary<string, GeoPoint> _locations
        = new ConcurrentDictionary<string, GeoPoint>(StringComparer.OrdinalIgnoreCase);

    static GeoPointModelBinder()
    {
        _locations["redmond"] = new GeoPoint() { Latitude = 47.67856, Longitude = -122.131 };
        _locations["paris"] = new GeoPoint() { Latitude = 48.856930, Longitude = 2.3412 };
        _locations["tokyo"] = new GeoPoint() { Latitude = 35.683208, Longitude = 139.80894 };
    }

    public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
    {
        if (bindingContext.ModelType != typeof(GeoPoint))
        {
            return false;
        }

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

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

        GeoPoint result;
        if (_locations.TryGetValue(key, out result) || GeoPoint.TryParse(key, out result))
        {
            bindingContext.Model = result;
            return true;
        }

        bindingContext.ModelState.AddModelError(
            bindingContext.ModelName, "Cannot convert value to Location");
        return false;
    }
}
公共类GeoPointModelBinder:IModelBinder
{
//已知地点的清单。
私有静态ConcurrentDictionary\u位置
=新的ConcurrentDictionary(StringComparer.OrdinalIgnoreCase);
静态地质点模型绑定器()
{
_地点[“redmond”]=新的地质点(){纬度=47.67856,经度=-122.131};
_地点[“巴黎”]=新地理点(){纬度=48.856930,经度=2.3412};
_地点[“东京”]=新地理点(){纬度=35.683208,经度=139.80894};
}
public bool BindModel(HttpActionContext actionContext,ModelBindingContext bindingContext)
{
if(bindingContext.ModelType!=typeof(地质点))
{
返回false;
}
ValueProviderResult val=bindingContext.ValueProvider.GetValue(
bindingContext.ModelName);
if(val==null)
{
返回false;
}
字符串键=val.RawValue作为字符串;
if(key==null)
{
bindingContext.ModelState.AddModelError(
bindingContext.ModelName,“错误的值类型”);
返回false;
}
地质点成果;
if(_locations.TryGetValue(键,输出结果)| | GeoPoint.TryParse(键,输出结果))
{
bindingContext.Model=result;
返回true;
}
bindingContext.ModelState.AddModelError(
bindingContext.ModelName,“无法将值转换为位置”);
返回false;
}
}

我相信NikoliaDante的答案在您有/api/users?id={{idHere}这样的路由的情况下有效。然而,如果您希望有更多的RESTful路由,下面的解决方案将为您提供解决方案。我刚刚在一个WebAPI2应用程序中对此进行了测试,效果很好。这将处理这样的用例:您可能有一个路由,比如/api/users/{{userId}}/something/{{somethingId}}

//Http Parameter Binding Magic
public class ObjectIdParameterBinding : HttpParameterBinding
{
    public ObjectIdParameterBinding(HttpParameterDescriptor p) : base(p){ }

    public override Task ExecuteBindingAsync(System.Web.Http.Metadata.ModelMetadataProvider metadataProvider, HttpActionContext actionContext, System.Threading.CancellationToken cancellationToken)
    {
        var value = actionContext.ControllerContext.RouteData.Values[Descriptor.ParameterName].ToString();
        SetValue(actionContext, ObjectId.Parse(value));

        var tsc = new TaskCompletionSource<object>();
        tsc.SetResult(null);
        return tsc.Task;
    }
}

//Binding Attribute
public class ObjectIdRouteBinderAttribute : ParameterBindingAttribute
{
    public override HttpParameterBinding GetBinding(HttpParameterDescriptor parameter)
    {
        return new ObjectIdParameterBinding(parameter);
    }
}

//Controller Example
[Route("api/users/{id}")]
public async Task<User> Get([ObjectIdRouteBinder] ObjectId id) 
{
    //Yay!
}
//Http参数绑定魔法
公共类ObjectdParameterBinding:HttpParameterBinding
{
公共ObjectdParameterBinding(HttpParameterDescriptor p):基(p){}
公共覆盖任务ExecuteBindingAsync(System.Web.Http.Metadata.ModelMetadataProvider metadataProvider、HttpActionContext actionContext、System.Threading.CancellationToken CancellationToken)
{
var value=actionContext.ControllerContext.RoutedData.Values[Descriptor.ParameterName].ToString();
SetValue(actionContext,ObjectId.Parse(value));
var tsc=new TaskCompletionSource();
tsc.SetResult(空);
返回tsc任务;
}
}
//绑定属性
公共类ObjectDuloteBinderAttribute:ParameterBindingAttribute
{
公共重写HttpParameterBinding GetBinding(HttpParameterDescriptor参数)
{
返回新的ObjectdParameterBinding(参数);
}
}
//控制器示例
[路由(“api/users/{id}”)]
公共异步任务Get([ObjectDuloteBinder]ObjectId)
{
//耶!
}

FromUri对于我的场景来说是不够的。我需要告诉ASP.NET如何将URL GET/Users/55b795827572761a08d735ac中给定的参数转换为ObjectId。这就是我需要BindModel的原因吗?@Matthias用于更复杂的映射,这些映射无法通过
FromUri
FromBody
推断。绑定器是保证事情按需要进行的方式。因此,“绑定器”可以用于我的URL,就像JSON转换器用于我的JSON负载一样。我将尝试实现BindModel。我还没有机会检查它,但我现在接受并投票。
public class GeoPointModelBinder : IModelBinder
{
    // List of known locations.
    private static ConcurrentDictionary<string, GeoPoint> _locations
        = new ConcurrentDictionary<string, GeoPoint>(StringComparer.OrdinalIgnoreCase);

    static GeoPointModelBinder()
    {
        _locations["redmond"] = new GeoPoint() { Latitude = 47.67856, Longitude = -122.131 };
        _locations["paris"] = new GeoPoint() { Latitude = 48.856930, Longitude = 2.3412 };
        _locations["tokyo"] = new GeoPoint() { Latitude = 35.683208, Longitude = 139.80894 };
    }

    public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
    {
        if (bindingContext.ModelType != typeof(GeoPoint))
        {
            return false;
        }

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

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

        GeoPoint result;
        if (_locations.TryGetValue(key, out result) || GeoPoint.TryParse(key, out result))
        {
            bindingContext.Model = result;
            return true;
        }

        bindingContext.ModelState.AddModelError(
            bindingContext.ModelName, "Cannot convert value to Location");
        return false;
    }
}
//Http Parameter Binding Magic
public class ObjectIdParameterBinding : HttpParameterBinding
{
    public ObjectIdParameterBinding(HttpParameterDescriptor p) : base(p){ }

    public override Task ExecuteBindingAsync(System.Web.Http.Metadata.ModelMetadataProvider metadataProvider, HttpActionContext actionContext, System.Threading.CancellationToken cancellationToken)
    {
        var value = actionContext.ControllerContext.RouteData.Values[Descriptor.ParameterName].ToString();
        SetValue(actionContext, ObjectId.Parse(value));

        var tsc = new TaskCompletionSource<object>();
        tsc.SetResult(null);
        return tsc.Task;
    }
}

//Binding Attribute
public class ObjectIdRouteBinderAttribute : ParameterBindingAttribute
{
    public override HttpParameterBinding GetBinding(HttpParameterDescriptor parameter)
    {
        return new ObjectIdParameterBinding(parameter);
    }
}

//Controller Example
[Route("api/users/{id}")]
public async Task<User> Get([ObjectIdRouteBinder] ObjectId id) 
{
    //Yay!
}