Attribute routing not working when controller is loaded dynamically (using custom controller selector)

  • Thread starter Thread starter dtf017
  • Start date Start date
D

dtf017

Guest
I'm creating a self hosted REST server (using Owin):

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

I create a static controller just to make sure it works ok with my settings:

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);
}
...

My startup class looks like this:

public class Startup
{
public void Configuration(IAppBuilder app)
{
var webApiConfiguration = ConfigureWebApi();
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;
}
}

Then i dynamically load another controller which has the same methods and definition exposed than the static one. To do that i use a custom controller selector:

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);
. .


They should both use the same routing settings.

I can call (HTTP GET) my static controller using attribute routing: http://localhost:12345/MyServer/api/Sample/Test/hello2
That works fine.


Problem is when i try the same thing on my dynamic controller: http://localhost:12345/MyServer/api/MyDynamic/Test/hello2

I get following error: { "Message": "The requested resource does not support http method 'GET'." }

It seems somehow the attribute routing is not enabled for my dynamic controller. If i use query parameters, it works just fine: http://localhost:12345/MyServer/api/MyDynamic/Test?data=hello

How can i make it work?

Thanks in advance for your help

Nick

Continue reading...
 
Back
Top