Маршрутизация атрибута не работает, когда контроллер загружается динамически (с помощью пользовательского селектора контроллера) - PullRequest
0 голосов
/ 08 октября 2019

Я создаю REST-сервер с собственным хостом (используя Owin):

string baseUri = string.Concat("http://+:58452/MyServer");
myserver = WebApp.Start<Startup>(baseUri);
Console.WriteLine("MyServer is listening at " + baseUri);
...

Я создаю статический контроллер, чтобы убедиться, что он работает нормально с моими настройками:

public class SampleController : ApiController
{
    public SampleController() { }

    [HttpGet]
    [Route("api/Sample/Test")]
    [Route("api/Sample/Test/{data}")]
    [ActionName("Test")]
    public string GetTest(string data)
    {
        return Test(data);
    }

    [HttpPost]
    [Route("api/Sample/Test")]
    public string Test([FromBody] string data)
    {
        return string.Concat("Test - Received ", data);
    }
...

Мой класс запуска выглядит так:

public class Startup
{
    // This method is required by Katana:
    public void Configuration(IAppBuilder app)
    {
        var webApiConfiguration = ConfigureWebApi();

        // Use the extension method provided by the WebApi.Owin library:
        app.UseWebApi(webApiConfiguration);
    }


    private HttpConfiguration ConfigureWebApi()
    {
        HttpConfiguration config = new HttpConfiguration();
        config.MapHttpAttributeRoutes();

        config.Routes.MapHttpRoute(
                    "DefaultApi",
                    "api/{controller}/{action}/{id}",
                    new { id = RouteParameter.Optional});

        DynControllerSelector custom = new DynControllerSelector(config);

        config.Services.Replace(typeof(IHttpControllerSelector), custom);

        return config;
    }
}

Затем я динамически загружаю другой контроллер, который имеет те же методы и определения, что и статический. Для этого я использую пользовательский селектор контроллера:

public DynControllerSelector(HttpConfiguration configuration) : base(configuration)
 {
    _Configuration = configuration;
    _ControlleDescriptorDict = new ConcurrentDictionary<string, HttpControllerDescriptor>();
 }
 public override HttpControllerDescriptor SelectController(HttpRequestMessage request)
 {
    HttpControllerDescriptor httpControllerDesc = null;
    try
    {
      IDictionary<string, HttpControllerDescriptor> controllers = GetControllerMapping();
      //string controllerName = base.GetControllerName(request); // is null for some reason
     // Just get the controler in a hack way for now
    string controllerName = request.RequestUri.LocalPath.Replace("/MyServer/api/", "");
    int idx = controllerName.IndexOf("/");
    controllerName = controllerName.Substring(0, idx);

    if (!controllers.ContainsKey(controllerName))
    {
       if (_ControlleDescriptorDict.TryGetValue(controllerName, out httpControllerDesc) == false)
       {
        lock (_mlock)
        {
            if (_ControlleDescriptorDict.TryGetValue(controllerName, out httpControllerDesc) == false) // Check that controller has not been created while we were waiting for the lock
            {
              string assemblyName = string.Concat(controllerName, ".dll");
              if (System.IO.File.Exists(assemblyName))
              {
                 Assembly assembly = Assembly.LoadFrom(assemblyName);
                 var types = assembly.GetTypes();
                 var matchedTypes = types.Where(i => typeof(IHttpController).IsAssignableFrom(i)).ToList();
                 var matchedController = matchedTypes.FirstOrDefault(i => i.Name.ToLower() == controllerName.ToLower() + "controller");
                 if (matchedController == null) throw new Exception(string.Concat("Failed to find controller ", controllerName, "Controller"));
                 httpControllerDesc = new HttpControllerDescriptor(_Configuration, controllerName, matchedController);

                _ControlleDescriptorDict.TryAdd(controllerName, httpControllerDesc);
               }
               else
               {
                throw new Exception(string.Concat("Failed to load assembly ", assemblyName));
                }
             }
          }
         }
      }
         else
            httpControllerDesc = base.SelectController(request);
. . .

Они должны использовать одинаковые настройки маршрутизации.

Я могу вызвать (HTTP GET) мой статический контроллер, используя атрибут маршрутизации: http://localhost:58452/MyServer/api/Sample/Test/hello2 Это прекрасно работает. Проблема в том, что когда я пытаюсь сделать то же самое на моем динамическом контроллере: http://localhost:58452/MyServer/api/MyDynamic/Test/hello2 Я получаю следующую ошибку: {"Message": "Запрошенный ресурс не поддерживает http-метод" GET "."}

Похоже, что маршрутизация атрибутов не включена для моего динамического контроллера. Если я использую параметры запроса, он работает просто отлично: http://localhost:58452/MyServer/api/MyDynamic/Test?data=hello

Как я могу заставить его работать?

Заранее спасибо за вашу помощь

Ник

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...