绑定asp.net mvc核心中的Guid参数

时间:2017-02-24 23:16:50

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

我想将Guid参数绑定到我的ASP.NET MVC Core API:

[FromHeader] Guid id

但它始终为空。如果我将参数更改为字符串并手动解析字符串中的Guid,那么我认为它不会将Guid视为可转换类型。

the documentation中说

  

在MVC中,简单类型是任何.NET基元类型或带有字符串类型转换器的类型。

Guids(GuidConverter)有一个类型转换器,但是ASP.NET MVC Core可能不知道它。

有谁知道如何将Guid参数与ASP.NET MVC Core绑定或如何告诉它使用GuidConverter?

4 个答案:

答案 0 :(得分:12)

我刚刚发现基本上ASP Core只支持将字符串绑定到字符串和字符串集合! (而从路由值绑定,查询字符串和正文支持任何复杂类型)

您可以查看public IModelBinder GetBinder(ModelBinderProviderContext context) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (context.BindingInfo.BindingSource != null && context.BindingInfo.BindingSource.CanAcceptDataFrom(BindingSource.Header)) { // We only support strings and collections of strings. Some cases can fail // at runtime due to collections we can't modify. if (context.Metadata.ModelType == typeof(string) || context.Metadata.ElementType == typeof(string)) { return new HeaderModelBinder(); } } return null; } source in Github并自行查看:

[FromHeader]

我已经提交了new issue,但与此同时我建议您绑定到字符串或创建自己的特定模型绑定器(将[ModelBinder]public class GuidHeaderModelBinder : IModelBinder { public Task BindModelAsync(ModelBindingContext bindingContext) { if (bindingContext.ModelType != typeof(Guid)) return Task.CompletedTask; if (!bindingContext.BindingSource.CanAcceptDataFrom(BindingSource.Header)) return Task.CompletedTask; var headerName = bindingContext.ModelName; var stringValue = bindingContext.HttpContext.Request.Headers[headerName]; bindingContext.ModelState.SetModelValue(bindingContext.ModelName, stringValue, stringValue); // Attempt to parse the guid if (Guid.TryParse(stringValue, out var valueAsGuid)) { bindingContext.Result = ModelBindingResult.Success(valueAsGuid); } return Task.CompletedTask; } } 合并到您的自己的活页夹)

修改

示例模型绑定器可能如下所示:

public IActionResult SampleAction(
    [FromHeader(Name = "my-guid")][ModelBinder(BinderType = typeof(GuidHeaderModelBinder))]Guid foo)
{
    return Json(new { foo });
}

这将是一个使用它的例子:

$.ajax({
  method: 'GET',
  headers: { 'my-guid': '70e9dfda-4982-4b88-96f9-d7d284a10cb4' }, 
  url: '/home/sampleaction'
});

您可以尝试使用,例如在浏览器中使用jquery:

cSplit

答案 1 :(得分:1)

[更新]

在2.1.0-preview2中对此进行了改进。您的代码现在可以正常工作了。您可以将标头中的非字符串类型绑定到您的参数。您只需要在启动类中设置兼容版本。

控制器

[HttpGet]
public Task<JsonResult> Get([FromHeader] Guid id)
{
    return new JsonResult(new {id});
}

启动

Services
  .AddMvc
  .SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

看看上面提到的同一Github讨论: https://github.com/aspnet/Mvc/issues/5859

答案 2 :(得分:0)

我是这样做的,不需要在控制器动作上添加其他属性。

模型活页夹

public class GuidHeaderModelBinder : IModelBinder
{
    public async Task BindModelAsync(ModelBindingContext BindingContext)
    {
        // Read HTTP header.
        string headerName = BindingContext.FieldName;
        if (BindingContext.HttpContext.Request.Headers.ContainsKey(headerName))
        {
            StringValues headerValues = BindingContext.HttpContext.Request.Headers[headerName];
            if (headerValues == StringValues.Empty)
            {
                // Value not found in HTTP header.  Substitute empty GUID.
                BindingContext.ModelState.SetModelValue(BindingContext.FieldName, headerValues, Guid.Empty.ToString());
                BindingContext.Result = ModelBindingResult.Success(Guid.Empty);
            }
            else
            {
                // Value found in HTTP header.
                string correlationIdText = headerValues[0];
                BindingContext.ModelState.SetModelValue(BindingContext.FieldName, headerValues, correlationIdText);
                // Parse GUID.
                BindingContext.Result = Guid.TryParse(correlationIdText, out Guid correlationId)
                    ? ModelBindingResult.Success(correlationId)
                    : ModelBindingResult.Failed();
            }
        }
        else
        {
            // HTTP header not found.
            BindingContext.Result = ModelBindingResult.Failed();
        }
        await Task.FromResult(default(object));
    }
}

Model Binder Provider (模型绑定程序提供程序)(验证模型绑定成功的条件)

public class GuidHeaderModelBinderProvider : IModelBinderProvider
{
    public IModelBinder GetBinder(ModelBinderProviderContext Context)
    {
        if (Context.Metadata.ModelType == typeof(Guid))
        {
            if (Context.BindingInfo.BindingSource == BindingSource.Header)
            {
                return new BinderTypeModelBinder(typeof(GuidHeaderModelBinder));
            }
        }
        return null;
    }
}

FooBar控制器操作

[HttpGet("getbars")]
public async Task<string> GetBarsAsync([FromHeader] Guid CorrelationId, int Count)
{
    Logger.Log(CorrelationId, $"Creating {Count} foo bars.");
    StringBuilder stringBuilder = new StringBuilder();
    for (int count = 0; count < Count; count++)
    {
        stringBuilder.Append("Bar! ");
    }
    return await Task.FromResult(stringBuilder.ToString());
}

启动

// Add MVC and configure model binding.
Services.AddMvc(Options =>
{
    Options.ModelBinderProviders.Insert(0, new GuidHeaderModelBinderProvider());
});

答案 3 :(得分:0)

最简单的方法是在这样的控制器操作中删除Guid类型的参数之前的属性:

public async Task<IActionResult> UpdateAsync(Guid ApplicantId, [FromBody]UpdateApplicantRequest request) {}

简单明了,希望对您有所帮助。