Web Api 2 Inheritance No route providing a controller name was found to match request URI - entity-framework

Basically I cannot get my Web Api 2 application to work.
First of all here are my requirements.
In my application I am creating a dozen of controllers ( ProductController, ItemController, SalesController...etc). There are 2 actions which are absolutely common in all my controllers:
FetchData, PostData
(Each controller then may implement a number of other methods which are sepcific to its business domain )
Instead of repeating these actions in every controllers like:
public class ProductController:ApiController{
[HttpPost]
public MyReturnJson FetchData( MyJsonInput Input){
....
return myJsonResult;
}
}
public class SalesController:ApiController{
[HttpPost]
public MyReturnJson FetchData( MyJsonInput Input){
....
return myJsonResult;
}
}
I decided to create a base controller MyBaseController:
public class MyBaseController : ApiController{
[HttpPost]
public MyReturnJson FetchData( MyJsonInput Input){
....
return myJsonResult;
}
}
with the 2 methods so every other controller would inherit them (It saves me from repeating them in every controller). The common base class has been defined and implemented in a separate assembly which is then referenced in my web project.
Then in my javascript client (using breeze) I call a specific controller like
breeze.EntityQuery.from('FetchData')
where my serviceName is 'my_api/product/'
(in the WebApiConfig, the routing table has been defined like:
config.Routes.MapHttpRoute(
name: "my_api",
routeTemplate: "my_api/{controller}/{action}"
);
But when the javascript code is executed I get the error message:
No route providing a controller name was found to match request URI
http://localhost:xxxxx/my_api/product/FetchData
If I don't use a common base class but instead repeat this method (FetchData) in every class (basically ProductController inherits directly from ApiController and not from MyBaseController) every thing works fine and my method is hit. I thing there is a problem with the inheritance scheme. Maybe there is something I don't get (first time using Web Api 2) or some constraints (routing, configuration...) I do not respect. Right now I am stuck and I would appreciate any suggestion which might point me to the right direction. Is inheritance allowed in Web Api 2?

I am not sure why your code is not working. But in the next link (http://www.asp.net/web-api/overview/releases/whats-new-in-aspnet-web-api-22#ARI) you can see an example of inheritance using attribute routing.
This is the code example:
public class BaseController : ApiController
{
[Route("{id:int}")]
public string Get(int id)
{
return "Success:" + id;
}
}
[RoutePrefix("api/values")]
public class ValuesController : BaseController
{
}
config.MapHttpAttributeRoutes(new CustomDirectRouteProvider());
public class CustomDirectRouteProvider : DefaultDirectRouteProvider
{
protected override IReadOnlyList<IDirectRouteFactory>
GetActionRouteFactories(HttpActionDescriptor actionDescriptor)
{
return actionDescriptor.GetCustomAttributes<IDirectRouteFactory>
(inherit: true);
}
}
I hope that it helps.

Related

GET and PUT methods for same route don't work if in separate classes

We're using specific route attributes for all our web api routes.
We want to split up a controller class, so we're moving some update functions out to a separate controller class.
We've subsequently got an odd situation with routing.
The original controller class looked like this:
[RoutePrefix("activities")]
public class ActivitiesController : ApiController
{
...
[Route("{activityId:int:min(1)}"), HttpPut]
public void Put(int activityId, [FromBody] NewActivity value) {}
[Route("{activityId:int:min(1)}"), HttpGet]
public dynamic Get(int activityId) {}
...
}
And we then split out the updates, so we end up with this:
[RoutePrefix("activities")]
public class ActivitiesUpdateController : ApiController
{
...
[Route("{activityId:int:min(1)}"), HttpPut]
public void Put(int activityId, [FromBody] NewActivity value) {}
...
}
[RoutePrefix("activities")]
public class ActivitiesController : ApiController
{
...
[Route("{activityId:int:min(1)}"), HttpGet]
public dynamic Get(int activityId) {}
...
}
If we then try to call either endpoint:
- PUT activities/42
- GET activities/42
We get the error:
Multiple controller types were found that match the URL. This can happen if attribute routes on multiple controllers match the requested URL.
The request has found the following matching controller types:
API.Controllers.ActivitiesUpdateController
API.Controllers.ActivitiesController
If both endpoints are in the same class (either the new one or the old), everything works correctly.
Different classes raises the error.
If I dump out the endpoints using ApiExplorer, both end points are where they should be and are not repeated in the other class, so there's no obvious duplication.
I've tried renaming functions, explicit routes (i.e. ~/activities/:id), adding HttpGet & HttpPut doesn't seem to make a difference.
Is this some weird "feature" where the same endpoint with different methods have to be in the same class?
It makes no sense.
Not to worry, I came across this after I posted - don't know how I missed it before:
Multiple controllers with same URL routes but different HTTP methods

Using my own service with Laravel4

In my app, I was testing Google Directions API with ajax, but since I was just testing all the logic was in the routes.php file. Now I want to do things the proper way and have three layers: route, controller and service.
So in the routes I tell Laravel which method should be executed:
Route::get('/search', 'DirectionsAPIController#search');
And the method just returns what the service is supposed to return:
class DirectionsAPIController extends BaseController {
public function search() {
$directionsSearchService = new DirectionsSearchService();
return $directionsSearchService->search(Input::all());
}
}
I created the service in app/libraries/Services/Directions and called it DirectionsSearchService.php and copied all the logic I developed in routes:
class DirectionsSearchService {
public function search($input = array()) {
$origin = $input['origin'];
$destination = $input['destination'];
$mode = $input['mode'];
// do stuf...
return $data;
}
}
I read the docs and some place else (and this too) and did what I was supposed to do to register a service:
class DirectionsAPIController extends BaseController {
public function search() {
App::register('libraries\Services\Directions\DirectionsSearchService');
$directionsSearchService = new DirectionsSearchService();
return $directionsSearchService->search(Input::all());
}
}
// app/libraries/Services/Directions/DirectionsSearchService.php
use Illuminate\Support\ServiceProvider;
class DirectionsSearchService extends ServiceProvider {
}
I also tried adding libraries\Services\Directions\DirectionsSearchService to the providers array in app/config/app.php.
However, I am getting this error:
HP Fatal error: Class
'libraries\Services\Directions\DirectionsSearchService' not found in
/home/user/www/my-app-laravel/bootstrap/compiled.php on line 549
What am I doing wrong? And what is the usual way to use your own services? I don't want to place all the logic in the controller...
2 main things that you are missing:
There is a difference between a ServiceProvider and your class. A service provider in Laravel tells Laravel where to go look for the service, but it does not contain the service logic itself. So DirectionsSearchService should not be both, imho.
You need to register your classes with composer.json so that autoloader knows that your class exists.
To keep it simple I'll go with Laravel IoC's automatic resolution and not using a service provider for now.
app/libraries/Services/Directions/DirectionsSearchService.php:
namespace Services\Directions;
class DirectionsSearchService
{
public function search($input = array())
{
// Your search logic
}
}
You might notice that DirectionsSearchService does not extend anything. Your service becomes very loosely coupled.
And in your DirectionsAPIController.php you do:
class DirectionsAPIController extends BaseController
{
protected $directionsSearchService;
public function __construct(Services\Directions\DirectionsSearchService $directionsSearchService)
{
$this->directionsSearchService = $directionsSearchService;
}
public function search()
{
return $this->directionsSearchService->search(Input::all());
}
}
With the code above, when Laravel tries to __construct() your controller, it will look for Services\Directions\DirectionsSearchService and injects into the controller for you automatically. In the constructor, we simply need to set it to an instance variable so your search() can use it when needed.
The second thing that you are missing is to register your classes with composer's autoload. Do this by adding to composer.json's autoload section:
"autoload": {
"classmap": [
... // Laravel's default classmap autoloads
],
"psr-4": {
"Services\\": "app/libraries/Services"
}
}
And do a composer dump-autoload after making changes to composer.json. And your code should be working again.
The suggestion above can also be better with a service provider and coding to the interface. It would make it easier to control what to inject into your controller, and hence easier to create and inject in a mock for testing.
It involves quite a few more steps so I won't mention that here, but you can read more in Exploring Laravel’s IoC container and Laravel 4 Controller Testing.

ASP.NET Web Api Routing Customization

I have WebApi controllers that end with the "Api" suffix in their names (For ex: StudentsApiController, InstructorsApiController). I do this to easily differentiate my MVC controllers from WebApi controllers. I want my WebApi routes to look similar to
http://localhost:50009/api/students/5 and not http://localhost:50009/api/studentsapi/5.
Currently to achieve this, I am setting up routes like
routes.MapHttpRoute(
name: "GetStudents",
routeTemplate: "api/students/{id}",
defaults: new { controller = "StudentsApi", id = RouteParameter.Optional });
routes.MapHttpRoute(
name: "GetInstructors",
routeTemplate: "api/instructors/{id}",
defaults: new { controller = "InstructorsApi", id = RouteParameter.Optional });
This is turning out to be very cumbersome as I have to add a route for each method in my controllers. I am hoping there should be an easy way to setup route templates that automatically adds the "api" suffix the controller name while processing routes.
Following #Youssef Moussaoui's direction I ended up writing the following code that solved the problem.
public class ApiControllerSelector : DefaultHttpControllerSelector
{
public ApiControllerSelector(HttpConfiguration configuration)
: base(configuration)
{
}
public override string GetControllerName(HttpRequestMessage request)
{
if (request == null)
throw new ArgumentNullException("request");
IHttpRouteData routeData = request.GetRouteData();
if (routeData == null)
return null;
// Look up controller in route data
object controllerName;
routeData.Values.TryGetValue("controller", out controllerName);
if (controllerName != null)
controllerName += "api";
return (string)controllerName;
}
}
And register it in Global.asax as
GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerSelector),
new ApiControllerSelector(GlobalConfiguration.Configuration));
Now that ASP.NET Web API 2 is out, there is a much less cumbersome way to do more complex routing like that you suggested, by using attribute routing.
At the top of your controller just add the following attribute:
[RoutePrefix("api/students")]
public class StudentsApiController : ApiController
{
...
}
And then before each API method:
[Route("{id}"]
public HttpResponseMessage Get(int id)
{
...
}
There is a bit of setup required, but the positives of doing routing this way are many. For one, you can put the routing with the controllers and methods that do the actual work, so you're never searching around wondering if you have the right route. Secondly and more importantly, it's much easier to do more complex routing, like having the controller name different from the route name (like you want) or having very complex patterns to match against.
I think the extensibility point you're looking for is the controller selector. You can create a class that derives from DefaultHttpControllerSelector and overrides the GetControllerName to strip out the "api" part. You can then register this controller selector on your service's configuration Services.
Following Youssef's comment on muruug's answer would look something like this
public class ApiControllerSelector : DefaultHttpControllerSelector
{
public ApiControllerSelector (HttpConfiguration configuration) : base(configuration) { }
public override string GetControllerName(HttpRequestMessage request)
{
return base.GetControllerName(request) + "api";
}
}

In asp.net mvc 2 : how to access http post data inside constructor of any controller

My controller has abstract base controller. I want to access the form post data inside abstract base class constructor. How can we do that ?
public abstract class AppController : Controller
{
public AppController()
{
// request post data required here
}
}
public class ProductController : AppController
{
public ProductController() { }
}
Purpose : Updating second dropdown on change of first dropdown. Both are on MASTER page.
Code given above is one of the 2 options to pass data to master page:
Add using ViewData in ALL the action methods.
Do it in only one place using abstract base controller - add the required data using ViewData inside its constructor and make our main controller class implement this abstract base controller class. So that we don't have to add the viewdata for master page in all action methods.
I don't know what is your final goal with this but this is something which is not recommended to be done in MVC. The Request object is not yet initialized in the constructor of the controller. You could try to use the native HttpContext object:
string foo = System.Web.HttpContext.Current.Request["foo"];
but that's something extremely bad and I would never recommend you doing this as now your controller is coupled to the static native HttpContext instance without any chance of unit testing it.
Instead of using the constructor you could override the Initialize method of your controller where you will have access to the request context and you could read posted data:
protected override void Initialize(System.Web.Routing.RequestContext requestContext)
{
base.Initialize(requestContext);
string foo = requestContext.HttpContext.Request["foo"];
}

Custom Logic and Proxy Classes in ADO.NET Data Services

I've just read "Injecting Custom Logic in ADO.NET Data Services" and my next question is, How do you get your [WebGet] method to show up in the client-side proxy classes? Sure, I can call this directly (RESTfully) with, say, WebClient but I thought the strong typing features in ADO.NET Data Services would "hide" this from me auto-magically.
So here we have:
public class MyService : DataService<MyDataSource>
{
// This method is called only once to initialize service-wide policies.
public static void InitializeService(IDataServiceConfiguration config)
{
config.SetEntitySetAccessRule("Customers", EntitySetRights.AllRead);
config.SetServiceOperationAccessRule("CustomersInCity", ServiceOperationRights.All);
}
[WebGet]
public IQueryable<MyDataSource.Customers> CustomersInCity(string city)
{
return from c in this.CurrentDataSource.Customers
where c.City == city
select c;
}
}
How can I get CustomersInCity() to show up in my client-side class defintions?
When you see your Odata in browser, you will see link ...
e.g. http://localhost:1234/odataService.svc
just write your method name after the link
for your method it will be something like this...
http://localhost:1234/odataService.svc/CustomersInCity?city="London"