Проблема в том, что ваш контроллер имеет одинаковую маршрутизацию для 2 разных методов, получающих разные параметры. Позвольте мне проиллюстрировать это на похожем примере, у вас может быть 2 метода, подобных этому:
Get(string entityName, long id)
Get(string entityname, string timestamp)
Пока это верно, по крайней мере, C# не дает вам ошибки, потому что это перегрузка параметры. Но с контроллером у вас есть проблема, когда pnet получает дополнительный параметр, он не знает, куда перенаправить ваш запрос. Вы можете изменить маршрут, который является одним из решений.
Это решение дает вам также возможность сопоставить ваш ввод со сложным типом, в противном случае используйте Ограничение маршрута для простых типов
Обычно я предпочитаю сохранять одинаковые имена и переносить параметры в DtoClass, IntDto и StringDto, например
public class IntDto
{
public int i { get; set; }
}
public class StringDto
{
public string i { get; set; }
}
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
[HttpGet]
public IActionResult Get(IntDto a)
{
return new JsonResult(a);
}
[HttpGet]
public IActionResult Get(StringDto i)
{
return new JsonResult(i);
}
}
, но, тем не менее, у вас есть ошибка. Чтобы связать ваш ввод с указанным типом c в ваших методах, я создаю ModelBinder, для этого сценария он ниже (см., Что я пытаюсь проанализировать параметр из строки запроса, но я использую заголовок дискриминатора который обычно используется для согласования содержимого между клиентом и сервером ( согласование содержимого ):
public class MyModelBinder : IModelBinder
{
public Task BindModelAsync(ModelBindingContext bindingContext)
{
if (bindingContext == null)
throw new ArgumentNullException(nameof(bindingContext));
dynamic model = null;
string contentType = bindingContext.HttpContext.Request.Headers.FirstOrDefault(x => x.Key == HeaderNames.Accept).Value;
var val = bindingContext.HttpContext.Request.QueryString.Value.Trim('?').Split('=')[1];
if (contentType == "application/myContentType.json")
{
model = new StringDto{i = val};
}
else model = new IntDto{ i = int.Parse(val)};
bindingContext.Result = ModelBindingResult.Success(model);
return Task.CompletedTask;
}
}
Затем необходимо создать ModelBinderProvider (см., что, если я получаю, пытается связать один из этих типов, затем я использую MyModelBinder)
public IModelBinder GetBinder(ModelBinderProviderContext context)
{
if (context.Metadata.ModelType == typeof(IntDto) || context.Metadata.ModelType == typeof(StringDto))
return new MyModelBinder();
return null;
}
и регистрирую его в контейнере
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers(options =>
{
options.ModelBinderProviders.Insert(0, new MyModelBinderProvider());
});
}
Пока вы не решили проблему, которая у вас есть, но мы близки. Чтобы выполнить действия контроллера сейчас, вам нужно передать тип заголовка по запросу: application / json или application / myContentType. json. Но для того, чтобы Поддерживая условную логику c, чтобы определить, является ли связанный метод действия действительным или нет для выбора для данного запроса, вы можете создать свой собственный ActionConstraint
. Basica Идея здесь заключается в том, чтобы украсить ваш ActionMethod этим атрибутом, чтобы пользователь не мог выполнить это действие, если он не передал правильный тип носителя. Ниже приведен код и как его использовать
[AttributeUsage(AttributeTargets.All, Inherited = true, AllowMultiple = true)]
public class RequestHeaderMatchesMediaTypeAttribute : Attribute, IActionConstraint
{
private readonly string[] _mediaTypes;
private readonly string _requestHeaderToMatch;
public RequestHeaderMatchesMediaTypeAttribute(string requestHeaderToMatch,
string[] mediaTypes)
{
_requestHeaderToMatch = requestHeaderToMatch;
_mediaTypes = mediaTypes;
}
public RequestHeaderMatchesMediaTypeAttribute(string requestHeaderToMatch,
string[] mediaTypes, int order)
{
_requestHeaderToMatch = requestHeaderToMatch;
_mediaTypes = mediaTypes;
Order = order;
}
public int Order { get; set; }
public bool Accept(ActionConstraintContext context)
{
var requestHeaders = context.RouteContext.HttpContext.Request.Headers;
if (!requestHeaders.ContainsKey(_requestHeaderToMatch))
{
return false;
}
// if one of the media types matches, return true
foreach (var mediaType in _mediaTypes)
{
var mediaTypeMatches = string.Equals(requestHeaders[_requestHeaderToMatch].ToString(),
mediaType, StringComparison.OrdinalIgnoreCase);
if (mediaTypeMatches)
{
return true;
}
}
return false;
}
}
Вот ваше последнее изменение:
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
[HttpGet]
[RequestHeaderMatchesMediaTypeAttribute("Accept", new[] { "application/json" })]
public IActionResult Get(IntDto a)
{
return new JsonResult(a);
}
[RequestHeaderMatchesMediaTypeAttribute("Accept", new[] { "application/myContentType.json" })]
[HttpGet]
public IActionResult Get(StringDto i)
{
return new JsonResult(i);
}
}
Теперь ошибка исчезнет, если вы запустите свое приложение. Но как вы передадите параметры ?: Этот метод попадет по этому методу:
public IActionResult Get(StringDto i)
{
return new JsonResult(i);
}
А этот другой:
public IActionResult Get(IntDto a)
{
return new JsonResult(a);
}
Запустите его и дайте мне знать