I have an existing webapi 2 application that needs a basic front end adding. The existing webapi controllers have been created in the Controllers directory root named xController yController.
Controllers
-XController.cs
-YController.cs
with the following route
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}"
);
Each one of these controllers needs an accompanying MVC controller. What i would like to do is to rename the API controllers to XApiController YApiController and use routing to ensure existing usages of the service done break. Then I can add standard MVC controllers for the front end.
Controllers
-XApiController (previously XContoller)
-XController
-YApiController (previously YController)
-YController
Can you not just use the RoutePrefix attribute to do this? then you can call your controllers whatever you want and just have the attribute decide where it should be hosted, there are pros and cons to controlling your routing at the controller level but it seems to be a common use case, so for example:
[RoutePrefix("api/home")]
public class SomeHomeController: ApiController
{
// ...
}
Controllers are separate types in each framework, and each framework can discover them regardless of their location (provided they have the right name). There is no reason to mess with routing to get your desired result. The only thing you need (assuming it is acceptable) is to put your controllers into a different namespace/folder so you can have 2 controllers (MVC and Web API) with the same name.
ApiControllers
-XController
-YController
Controllers
-XController
-YController
If you ask me, it is still better to keep the MVC and API controllers in a separate location even if you cannot deploy them as separate applications.
Related
I have 2 separate projects:
Web API
Web application (GUI)
Both will have the same logic and code, it's just their return type that are different.
Obviously the API will return json, and the web app will have views.
My question: is there a way to use the same controllers and actions for both web app and api? I just don't want to repeat myself and use less code.
What I have found is that you can have multiple routes for your controller, and then you can get the current url in your controller.
So something like:
[Route("api/[controller]")]
[Route("[controller]")]
class MyController:ControllerBase
{
[HttpGet]
public IActionResult Hi()
{
// if (url startwith "api")
//return json
//otherwise return some view
}
}
I didn't try myself because I wasn't sure if this was a right way to solve it or not, and on the other hand I have to put that if check in all the methods...
Since you have two different projects so you have to use different controllers and actions. You cannot use same physical controllers and actions from two different projects.
I'm trying to choose between MVC and WebApi, so some situations WebApi is better (documentation, testing and ...) and for some situation MVC controllers are better (when rendering Razor pages and so on)
But when I create an asp.net MVC webapplication, none of controllers inhertited from ApiController will be detected and If I create an asp.net WebApi web application, none of Controllers inheriting from System.Web.Mvc.Controller will be detected.
I compared web.config of these 2 web apps, nothing is different.
I have 2 questions
If both web.config are same, then how one app detects only controllers inherit from System.Web.Mvc.Controller and another app detects only controllers inherit from ApiController? what's different between them?
Can I configure web app to support both controller types?
If you right click and "go to definition" of both controllers you will discover they are of different namespaces and even implement different base classes, so you won't be able to have a class inherit from both "ApiController" (Web-Api) & "Controller"(MVC) at the same time (I much as I know).
However, if you need both controllers in the same projects, you can just right-click and add either a "Web-Api" controller or "MVC controller".
And then you can actually instantiate and use the "Web-Api" controller on the MVC controller code
The steps You needed to perform were:
1- Make Mvc Web Application Add reference to System.Web.Http.WebHost.
2- Add App_Start\WebApiConfig.cs (see code snippet below).
3- Import namespace System.Web.Http in Global.asax.cs.
4- Call WebApiConfig.Register(GlobalConfiguration.Configuration) in MvcApplication.Application_Start() (in file Global.asax.cs), before registering the default Web Application route as that would otherwise take precedence.
5- Add a controller deriving from System.Web.Http.ApiController.
I could then learn enough from the tutorial (Your First ASP.NET Web API) to define my API controller.
App_Start\WebApiConfig.cs:
using System.Web.Http;
class WebApiConfig
{
public static void Register(HttpConfiguration configuration)
{
configuration.Routes.MapHttpRoute("API Default", "api/{controller}/{id}",
new { id = RouteParameter.Optional });
}
}
Global.asax.cs:
using System.Web.Http;
...
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
WebApiConfig.Register(GlobalConfiguration.Configuration);
RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
the NuGet package Microsoft.AspNet.WebApi must be installed for the above to work.
I have a website made in C# (http://my.site/), and now i have a Web API project that i want to merge to that domain and listen on http://my.site/api. They are 2 separate projects in VS2013.
I tried uploading Web API to /api/ subfolder in the server and map a MVC route to it (WebApi route in WebApiConfig.cs still routeTemplate: "api/{controller}/{id}"), expecting the default (Home) MVC controller to respond in /api/. The MVC route (in WebAPI's MVC routing):
routes.MapRoute(
name: "Default",
url: "{controller}", //Also api/{controller}
defaults: new { controller = "Home", action = "Get", id = UrlParameter.Optional }
);
But i get "Server Error 404" when accessing http://my.site/api/ / http://my.site/api/home etc. I don't understand the nature of this error (most likely settings in the C# website in root folder), but one would think IIS would serve the default app inside the /api/ folder.
So i want to know if adding WebApiConfig.Register(GlobalConfiguration.Configuration); to Global.asax (Application_Start()) and adding WebApiConfig.cs to App_Start folder of the C# project (and using the respective namespaces) will solve the issue. This seem too simple to be true so i doubt it will work, so i need someone to point me in the correct direction, or i will commit the sin of going back to asmx.
If not, how can i have C# website and a WebAPI on same domain?
You are wanting to run two separate dlls (each with their own routing rules) within the same bin folder on your server. That could definitely cause some conflicts in routing on your site. A proper way to do this would be to host your api project on a separate server and use a sub-domain, such as http://api.my.site/. That way you ensure that your C# site (http://my.site/)would have access to the api (http://api.my.site/). And your dlls, including routing rules, would remain separate.
I have two routes in my application, each in a different Controller, that look like this:
[Route("forgot-password", Order = 1)]
[Route("{variable}", Order = 2)]
When I run the application I get the exception:
Multiple controller types were found that match the URL. This can
happen if attribute routes on multiple controllers match the requested
URL.
Remember these actions are in different Controllers. The Order attribute doesn't seem to work across Controllers!.
How can I get this scenario to work in asp.net mvc routing? I want to use attribute based routing and I don't want to change my urls.
The mechanism behind the error is explained here (I guess you are using Web API). Shortly put, precedence is honored only inside a controller.
Also, it is unclear for me why you want such a generic route like:
[Route("{variable}")]
The problem is that all routes in your application have been stored together. Even if it is located in different controllers, it is the same type, so they can "see" each other. In your case "forgot-password" and "{variable}" have the same format, that's why error about multiple routes has been displayed. As #NightOwl888 said, you may use RouteConfig to create a routes, but in that case you have to change your routing values.
I have an existing asp.net-mvc web site and now I need to expose of a few of my calls to external applications that are only used within my site right now. This is all happening within an intranet within my company.
I have read this page which explains Web API versus controller actions as well as this SOF question which seems to have a similar issue but the answers seem a bit outdated. So I am trying to determine given the latest available functionality what is the simplest solution to meet my requirement.
In my case, since I already have the same controller actions used within my current website then WEB API doesn't really make sense but if I google anything around asp.net-mvc authentication or security I only see articles around web API.
Given that, I am trying to figure out best practice for exposing my controller action to another application.
In an ideal world you would convert the app to web api controllers as someone else suggested but to be more pragmatic you can implement an interim solution where you expose only the required calls via extending ApiController
You did not mention which version of MVC your current app is using nor did you mention how your current Controllers return data to the web app.
I will therefore assume you return data via a view model and razor views. eg:
public class ProductsController : Controller
{
public void Index()
{
var view = new ProductsListView();
view.Products = _repository.GetProducts();
return View(view);
}
}
Suppose now you want to expose the products list via a REST-like api?
First check you have web api installed (via nuget)
Install-Package Microsoft.AspNet.WebApi
(again i'm not sure what ver of asp.net you are on so this process may differ between versions)
Now in your public void Application_Start()
GlobalConfiguration.Configure(WebApiConfig.Register);//add this before! line below
RouteConfig.RegisterRoutes(RouteTable.Routes);//this line shld already exist
and in WebApiConfig
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
I like to create a dedicated folder called ApiControllers and add controllers with the same name; this way you can have controllers with the same names as they are in different namespaces:
namespace YourApp.Web.ApiControllers
{
[AllowAnonymous]
public class ProductsController : ApiController
{
[HttpGet]
public HttpResponseMessage Products()
{
var result = new ProductResult();//you could also use the view class ProductsListView
result.Products = _repository.GetProducts();
return Request.CreateResponse(httpStatusCode, result);
}
}
}
You can then access this via yourapp.com/api/products
nb, try to reduce duplication of code inside controllers - this can be acheived by extracting common parts into service classes.
While I would highly recommend using a web service architecture, such as Web API or ServiceStack, you can expose controller actions.
You'll first want to decorate the actions with the [AllowAnonymous] attribute. Then, in your web.config you'll need to add the following code block to the configuration section for each action you want exposed.
<location path="ControllerNameHere/ActionNameHere">
<system.web>
<authorization>
<allow users="*" />
</authorization>
</system.web>
</location>
As you may have guessed, this becomes very repetitive and annoying, which is why web services would be a great choice.
I had a similar requirement where website 2 needed to call some controller actions from website 1. Since there was no changes in the logic I wanted to avoid the whole rewrite using web API. I created another set of controller and actions that would return Json. The new controller actions would call the original controller actions and then convert the result data to json before returning. The other applications (website 2) would then make http get and post requests to get json data and deserialize it internally. Worked nicely in my case.
I didn't have to put a security layer over the json based actions as they were public, but you might need one to authenticate the requests.
Although webapi is the best way but you don't need to convert your controller/actions to webapi at all.
You could easily achieve what you are after by restricting the controller/actions by IP addresses from your intranet. Just make sure that all intranet sites reside on the same domain other cross domain jquery ajax calls will not work.
Here is an eg. Restrict access to a specific controller by IP address in ASP.NET MVC Beta
An alternative is to use basic authentication and only allow a hardcoded userid/password to access those controller/actions and call via ajax:
beforeSend: function (xhr) {
xhr.setRequestHeader ("Authorization", "Basic " + btoa(username + ":" + password));
},