如何在控制器操作上使用多态性一种方法



我试图将ASP.NET WEB API转换为ASP.NET CORE WEB API,但出现错误

我在ASP.NET WebAPI 中的代码

public class TestController : ApiController
{
// GET /test
public object Get()
{
return "get";
}
// GET /test?id={id}
public object Get(string id)
{
return id;
}
// GET /test?id={id}&anyParam={anyParam}
public object Get(string id, string anyParam)
{
return id + anyParam;
}
}
config.Routes.MapHttpRoute("Controller", "{controller}");

尝试将其转换为ASP.NET Core 2.1/3.0

[ApiController]
[Route("{controller}")]
public class TestController : ControllerBase
{
// GET /test
public object Get()
{
return "get";
}
// GET /test?id={id}
public object Get(string id)
{
return id;
}
// GET /test?id={id}&anyParam={anyParam}
public object Get(string id, string anyParam)
{
return id + anyParam;
}
}
services.AddControllers(); 
app.UseRouting();
app.UseEndpoints(endpoints => { endpoints.MapControllers(); });

我在ASP.NET Core 中

模糊匹配异常:请求匹配多个端点

明智的解决方案是只有一个方法,它接受三个参数。

但是,明智的解决方案并不能提供最有趣的stackerflow答案,因此以下是如何使用两个自定义属性来实现这一点,一个属性说明所需的参数,另一个属性则说明排除了哪些参数:

public class RequireRequestParameterAttribute : ActionMethodSelectorAttribute
{
private readonly string[] _requiredNames;
public RequireRequestParameterAttribute(params string[] names)
{
this._requiredNames = names;
}
public override bool IsValidForRequest(
RouteContext routeContext,
ActionDescriptor action
) =>
this._requiredNames
.All(
routeContext
.HttpContext
.Request
.Query
.ContainsKey
);
}
public class DisallowRequestParameterAttribute : ActionMethodSelectorAttribute
{
private readonly string[] _forbiddenNames;
public DisallowRequestParameterAttribute(params string[] names)
{
this._forbiddenNames = names;
}
public override bool IsValidForRequest(
RouteContext routeContext,
ActionDescriptor action
) =>
!(this._forbiddenNames
.Any(
routeContext
.HttpContext
.Request
.Query
.ContainsKey
)
);
}

现在您可以按如下方式应用属性:

[ApiController]
[Route("[controller]")]
public class TestController : ControllerBase
{
// GET test
public object Get()
{
return "Get";
}

// GET test?id={id}
[RequireRequestParameter("id")]
[DisallowRequestParameter("anyParam")]
public object Get(string id)
{
return id;
}
// GET test?id={id}&anyParam={anyParam}
[RequireRequestParameter("id", "anyParam")]
public object Get(string id, string anyParam)
{
return $"{id}: {anyParam}";
}
}

这意味着,如果添加具有第三个参数的另一个方法,则将承担在其他方法上添加或修改DisallowRequestParameter属性的维护负担。

我在操作中查看您生成的URL,它们都是导致AmbiguousMatchException/test,因为您的参数是GET并且是可选的。

我认为您可以在操作上使用相同的名称,但需要在操作上定义不同的ROUTE attribute(不同URL(

例如。不能在控制器操作上使用带有多态性的默认路由。

[Route("Home/About")]

MVC控制器现在在内部进行控制器映射使用端点。

如果应用程序使用属性路由,则添加MapControllers。

https://learn.microsoft.com/cs-cz/aspnet/core/mvc/controllers/routing?view=aspnetcore-3.0#属性路由

感谢daremachine的回答,我能够在谷歌上找到信息

在ASP.NET核心中的第一步,我们需要继承ActionMethodSelectorAttribute的类

public class RequireRequestValueAttribute : ActionMethodSelectorAttribute
{
public RequireRequestValueAttribute(string name, string value = null)
{
Name = name;
Value = value;
}
public string Name { get; }
public string Value { get; }
public StringComparison ComparisonType { get; } = StringComparison.OrdinalIgnoreCase;
private bool ValueIsValid(object value)
{
return ValueIsValid(value?.ToString());
}
private bool ValueIsValid(string value)
{
if (Value == null)
{
return true;
}
return string.Equals(value, Value, ComparisonType);
}
public override bool IsValidForRequest(RouteContext routeContext, ActionDescriptor action)
{
var value = default(object);
if (routeContext.RouteData.Values.TryGetValue(Name, out value) && ValueIsValid(value))
return true;
if (routeContext.RouteData.DataTokens.TryGetValue(Name, out value) && ValueIsValid(value))
return true;
if (routeContext.HttpContext.Request.Query.ContainsKey(Name))
{
var values = routeContext.HttpContext.Request.Query[Name];
if (values.Count <= 0)
{
if (ValueIsValid(null))
return true;
}
else if (values.Any(v => ValueIsValid(v)))
return true;
}
return false;
}
}

然后我们可以添加到问题方法[RequireRequestValue("")]中,控制器将看起来像这个

[ApiController]
[Route("{controller}")]
public class TestController : ControllerBase
{
// GET /test
public object Get()
{
return "get";
}
// GET /test?id={id}
[RequireRequestValue("id")]
public object Get(string id)
{
return id;
}
}

但它不能多态两个相似的字段,在我的问题中键入id

对于asp net core 2。如果尝试实现与web api控制器中相同的逻辑,请使用Microsoft.AspNetCore.Mvc.WebApiCompatSigm。此nuget包在ASP.NET Core Mvc中提供与ASP.NET web api 2的兼容性,以简化现有web api实现的迁移。请检查这个答案。从ASP.NET Core 3.0开始,Microsoft.AspNetCore.Mvc.WebApiCompatShe包不再可用。

相关内容

最新更新