C# Web Services Routing Controller to Defined URL - c#

I am new to C#, committing to a little Spike. I have built a few POCO OWIN self-hosting services and am trying to create a controller but guides and documentation everywhere appear to be pointing me in the incorrect direction.
I am adding default mapping to a configuration method inside a startup class. Then in my controller I have a simple GET method. This works like a charm, when I send a request to it using the url defined in my startup routing the method gets invoked. But now I need to set up a second method to be invoked by a new url.
I don't understand what I am missing and what I am not understanding but everything I attempt does not work for me:
relevant code in the controller:
// GET api/ManagedService
public string[] Get()
{
Start();
return new string[]
{
"Job Processed."
};
}
Relevant code in my startup class:
HttpConfiguration config = new HttpConfiguration();
config.EnableCors();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/start"
);
So on visiting api/{controller}/start I invoke my get but I want to invoke a different method with api/{controller}/receiptandsend.

I'm not 100% sure I understand what the problem is but try to change your routeTemplate to "api/{controller}/{action}" instead. The routeTemplate you are using assumes that you have an action (method) called start on every controller. Alternatively you could try to add another route, something like name: "anotherOne", routeTemplate: "api/{controller}/receiptandsend" but I don't think that is really the way to do it correctly.
edit: By the way, your Get method should probably be named something else, like StartJob or something, "Get" seems a bit misleading seeing that you don't get anything back except a text saying that you started some other process.

Related

Cannot get ASP.NET Web API routing to work at all

I am trying to refactor an old setup, the end goal will be that I will have a functional REST API. I am getting rid of an old NuGet service and I sort of have to rebuild everything now. I am trying to set it up using ASP.NET Web API. This will include 60+ routes (like "www.website.com/cars/{id}/engine" "www.website.com/inventory/{id}" etc..)
I have tried attribute routing and conventional routing, and nothing seems to work. I get 404's no matter what I seem to try. I am probably just not doing either of them correctly.
Here is how I am setting up configuration (I am using a self hosting package btw but this is the main configuration point):
public class SomeHostClass
{
public void Configuration(IAppBuilder app)
{
HttpConfiguration config = new HttpConfiguration();
//If I am trying attribute based routing, uncomment this
//config.MapHttpAttributeRoutes();
Register(config.Routes);
// I think I need this at all times?
app.UseWebApi(config);
}
public void Register(HttpRouteCollection routes)
{
// One of many other routes.MapHttpRoute() calls
routes.MapHttpRoute(
name: "Cars",
routeTemplate: "cars/{id}/engine",
defaults: new
{
controller = "CarController",
action = "Get"
},
constraints: null);
}
}
Then here is my Car Controller:
public class CarController : ApiController
{
[HttpGet]
public object Get([FromUri] CarDTO carObject)
{
// Some code calling a private worker method
return WorkerMethod();
}
private object WorkerMethod()
{
// Worker method do stuff, return
}
}
This Get() method is never called and a 404 is returned.
Another note: I have tried using reflection to register all the routes, which slims down the code. I'll debug it and it looks like all the routes have been configured correctly within the HttpConfiguration.routes but I will get 404's still. Even without reflection doing it the way shown above- if I debug and look at the values they all seem correct, but don't work.
Another Note: I should also mention that this is the error I usually get along with the 404.
{"Message":"No HTTP resource was found that matches the request URI 'http://localhost:8000/cars/1/engine'.","MessageDetail":"No type was found that matches the controller named 'CarController'."}
How do I get these routes recognized and stop returning 404's and start returning my data?
If this is a bad way of going about this- what's the best way?

MapHttpRoute to the Swashbuckle Swagger UI to use custom handler

I've got Swashbuckle going in my web api project. I want to get a custom handler invoked only when a user tries to hit the swagger ui page. I don't want to add the handler to the pipeline.
I thought something like this might work but it doesn't:
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "SwaggerUI",
routeTemplate: "docsite/{*assetPath}",
defaults: null,
constraints: null,
handler: new MyHandler() { InnerHandler = new HttpControllerDispatcher(config) }
I use route attributes everywhere else in the project so I map those attributes first.
My swagger config is using
.EnableSwaggerUi("docsite/{*assetPath}",c =>
hence the docsite route.
I don't want to add the handler to the pipeline because I don't want it to get called with every web api call. I'm using it to restrict access to the swagger UI.
Also I'm using OWIN to authenticate one particular api so I get this error when I try to call that api
The 'DelegatingHandler' list is invalid because the property 'InnerHandler' of 'MyHandler' is not null.
Parameter name: handlers
Figured I can avoid the error by just making sure the handler only happens when I do a swagger ui route.
Who wants to help!

NopCommerce code creates multiple null reference exceptions while using ASP.NET Web API

I am facing an issue currently with using ASP.NET Web API for the NopCommerce website which I need to connect to my cross-platform application.
The code breaks when I call the API. It produces an exception at:
var scope = EngineContext.Current.ContainerManager.Scope()
In the task.cs page.
I have tried debugging the code, but the exception is not generated regularly; sometimes it comes and sometimes not. I did, however, find some points where it breaks:
var sis = EngineContext.Current.Resolve<StoreInformationSettings>().
I have tried loading it till it loads. i.e., putting it inside a while statement as:
var sis = EngineContext.Current.Resolve<StoreInformationSettings>()`
while(sis == null)
{
sis = EngineContext.Current.Resolve<StoreInformationSettings>()
}
And similarly, a few more instances. This implies it loads, but after a delay, maybe.
There was an instruction in the nopcommerece forum to update the autofac package, which I did.
All the Autofac Nugets are tried individually in Nop.Web.
With reference to this link here, I have tried fixing, but it didn't solve my problem.
I came to the conclusion that it has some issue with the Autofac DI settings (not sure). Or is it that NopCommerce is built not to support APIs?
As Mr. Rigueira suggested, I have tried to register the route from the route configuration class inside my plugin itself.
The route configuration for the API is here:
public void RegisterRoutes(RouteCollection routes)
{
GlobalConfiguration.Configure(config =>
{
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { controller = "TestApi", id = RouteParameter.Optional }
);
});
}
Still, it does not seem to make any difference.
I tried registering the route from the Plugin in the normal pattern:
public void RegisterRoutes(RouteCollection routes)
{
routes.MapRoute(
"WebApi",
"api/{controller}/{action}/{id}",
new { controller = "WebApi", action = "", id = RouteParameter.Optional },
new[] { "Nop.Plugin.WebApi.EduAwake.Controllers" }
);
}
Still no go.
here's the error i get :
Multiple types were found that match the controller named 'Topic'. This can happen if the route that services this request ('api/{controller}/{action}/{id}') does not specify namespaces to search for a controller that matches the request. If this is the case, register this route by calling an overload of the 'MapRoute' method that takes a 'namespaces' parameter.
Line 13: <div class="col-md-12 padding-0" id="home-topic" style="margin-left:-14px;">
Line 14: <div id="home-topic-content" style="width:104%;">
Line 15: #Html.Action("TopicBlock", "Topic", new { systemName = "HomePageText" })
Line 16: </div>
Line 17: </div>
in index.cshtml.
this seems to be a hopeless condition.
I have been working on this since months!
Checking your code would be advisable but, most likely, you have by-passed nopcommerce when registering Web API, and now you're trying to use dependencies before they have been registered in the usual flow. That's why they eventually appear while you're waiting in the loop (I can't imagine how you have found such a workaround anyway...).
As a solution, you should integrate Web API using a plugin and not by modifying the original source code. I did it in the past, and it is not hard. There used to be a couple of samples for that if I don't recall badly.

WebApi 2 Route Attribute not working unless using parameter

I have a controller List
[Route("api/cache/list")]
[HttpGet]
public IEnumerable<string> List()
{
...
}
But i get a 404 if i try to go to localhost:12121/api/cache/list. My webapi config looks like this:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Configure Web API to use only bearer token authentication.
//config.SuppressDefaultHostAuthentication();
//config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
// Web API routes
config.MapHttpAttributeRoutes();
config.Formatters.Remove(config.Formatters.XmlFormatter);
//config.Routes.MapHttpRoute(
// name: "DefaultApi",
// routeTemplate: "api/{controller}/{id}",
// defaults: new { id = RouteParameter.Optional }
//);
}
}
On the other hand if i change that controller to
[Route("api/cache/list/{id}")]
[HttpGet]
public IEnumerable<string> List(int id =0)
{
...
}
It will work. Ive tried doing it without the id as a parameter, still doenst work. What am I doing wrong here?
Extra Info:
I do have a strange setup. My WebApiConfig.cs and global.cs are in a different project. The project which has my controller will then reference the project with the WebApiConfig.cs
Rather than giving the param a default value, try making your id param nullable:
public IEnumerable<string> List(int? id)
Then check for null in code. This also helps differentiate a passed zero from an omitted param value.
I wasnt able to figure out how to fix the problem exactly but I did find a way around my problem.
First I correctly identified that when my routing was in a single assembly the exact same code worked fine. When the routing for my project in a different assembly makes it difficult for config.MapHttpAttributeRoutes(); to correctly identify attribute routes.
On the other hand using a RoutePrefix seemed to fix my issue.
Im not going to set this as my answer because I feel it doesn't truly address the problem, but I felt it would be informational to anyone who comes along this question.

Unit testing WebApi routes with custom handlers

I'm having a problem testing routes and I think it's due to the route using a custom handler.
This question points to a similar issue, but doesn't quite fix what I'm doing.
I have a RouteConfiguration class that simply houses the route definitions to enable me to pull them in for the application as well as any testing routines:
// the route
ApiRoutes.MapHttpRoute(
name: "Custom",
routeTemplate: "api/service/{service}/{method}/{arguments}",
defaults: new { arguments = RouteParameter.Optional },
constraints: null,
handler: new ServiceDispatcher(_httpConfiguration, _controllerHelper)
);
Now when trying to test this using a similar pattern to this way of mocking the route it doesn't find the route (404). The select part looks like this (other code in this article is not shown):
HttpRequestMessage message = new HttpRequestMessage(HttpMethod.Get, "http://localhost/api/service/foo/bar/foobar");
DefaultHttpControllerSelector controllerSelector = new DefaultHttpControllerSelector(configuration);
HttpControllerDescriptor descriptor = controllerSelector.SelectController(message);
My (educated?) guess is this DefaultHttpControllerSelector but I don't know how or if it can be changed to support what I'm doing.
So, can I make this current routine work using custom handlers or am I barking up the wrong tree?
When you have a MessageHandler attached to the route, the controller dispatcher is never even called. It doesn't get that far.
If you want to test the routes, I would just call
var routeDate = config.Routes.GetRouteData(request);
Then you can check the route values and test for the service, method and arguments parameters.

Categories

Resources