My application has MVC controllers and WebApi controllers. Up to this point, I've been able to push any logic shared between the controllers into a BaseController and BaseApiController, respectively.
Now I have a situation where both an API controller and MVC controller are doing the same thing - registering a new user account. This process is a bit complex because I have a multi-tenant application, and looks something like this:
// MVCController : BaseController
public ActionResult Register(RegisterModel model) {
// see if the model is valid
// check and make sure the credentials check out with policy requirements
// add the user to the user table if they aren't already there
// create a tenancy
// assign cookie
}
Most of the actual work is pushed off into the service layer, but the calls and conditions take up about 20 lines of code that I'd rather not copy and paste into the analogous WebApi controller.
So I'm wondering if I can somehow have both my BaseController and BaseApiController inherit from a generic controller where I can put this auth code. What's the recommended approach here?
Unless I am missing something from your question, I would refactor that piece of code into a Util class that lives in your UI project. Then both your MVC controller and WebAPI controller can call it.
This approach is in-line with Composition over inheritance design principle.
If you cannot move the logic out into it's own library and then share it then I would probably see about calling the web api from mvc. See this post for an example on doing that: https://stackoverflow.com/a/13206631/426422
Related
We have an ASP.NET Core Web API running on .NET 5. It has got many controllers and routes that are sometimes protected via the Authorize attribute and sometimes they are public.
[ApiController]
[Route("[controller]")]
public class UserController : ControllerBase {
[HttpGet("me")]
public IActionResult GetMyPublicInformation()
{
// code...
}
[HttpGet("me")]
[Authorize]
public IActionResult GetMyPrivateInformation()
{
// code...
}
}
Well now I would like to publish these REST routes through different HTTP Routes, depending on the Authorization requirement. For example, the route GetPublicInformation does not require authorization. That route should be available under public/user/me. Whereas the method GetMyPrivateInformation does require authorization and should be published under the route secure/user/me.
Of coure, I am aware that I can define the route manually in the HttpGet attribute (i.e. [HttpGet("public/user/me")), but - besides that I'm lazy - it would be error prone because we have the information available twice: Once with in the manual route definition (HttpGet) and once in the Authorize attribute. So if someone forgets to change one of the two attributes, we get an inconsistency.
Question: What are my options to automate this URL rewriting (I'm thinking of middleware)? Are there any drawbacks you see using this approach? I have been fighting this idea because I don't like extra magic sauce in my codebase. I prefer explicity, that's why I'm going for the manual route naming right now...
By the way: I have to take this on me because of limitations in Microsoft's MSAL library. I believe I shouldn't have to do this because we host an OpenAPI definition on which routes are and which routes aren't authorized. That should be enough in most cases.
I'm new to asp.net mvc and web api. I'm reading a book which says:
ASP.NET MVC uses: System.Web.HttpRequest
and Web API Equivalent is System.Net.Http.HttpRequestMessage
and below is a picture that describes the request and result flow of web api
So my question is, how does hosting environment(which will typically be IIS) know that it should create a HttpRequestMessage object to represent the request from the client? I mean if the application is a MVC application, IIS should create a HttpRequest object instead of HttpRequestMessage, so how does IIS know which one to create?
As you can see from the picture you posted, the HttpRequestMessage exists only inside the "hosting" environment, web browser client does not know anything about that.
In the "hosting" world, IIS app pool is running the code you have built and deployed which knows very well wich framewok you are using as your code also contains the using assemblies you listed, System.Web... or System.Net...
Consider that even if you have shown separation between hosting, Controller and Action, all of that is running in same App Pool in IIS which, again, runs your code so knows what it is about as your IL assemblies were built from your specific source code.
I am not sure if I understand your question but this might be what you're looking for:
I mean if the application is a MVC application, IIS should create a
HttpRequest object instead of HttpRequestMessage, so how does IIS know
which one to create?
You must remember how you differentiate between a normal MVC Controller and a Web API Controller...
WebAPI Controllers enforces this annotation [ApiController] and must inherits from ControllerBase:
[ApiController]
public class PeopleController : ControllerBase {
//Your API methods here
}
A normal MVC Controller only inherits from Controller base class:
public class PeopleController : Controller {
//Your Action methods here...
}
Those already create configuration for your APP which becomes easier for you Hosting environment to know what is going and what to return when.
I hope you find this helpful.
Thanks for your time , I have a simple question, in an asp.net MVC application, inside controllers is it possible that along with some methods returning View (ActionMethods) other could act as (or return) Json as a Web API (could be called from external apps).
Just trying to do a proper separations, hence trying to understand.
Thanks much.
You can make an action function like an API. Try something like the this.
// Controller/Action
[HttpGet]
public ActionResult IAmSpecial()
{
if (Request.IsAjaxRequest())
{
string[] objects = new string[] { "Foo", "Bar" };
return Json(objects);
}
return View();
}
This will return the IAmSpecial view if you browse to {domain}/{Controller}/IAmSpecial while it will return a JSON result if you use an AJAX Http Get request on the same url.
while it is possible to have controller methods which return Json data only, there are a number of considerations when you want to expose that data outside of the UI app.
Since you have an MVC app, I expect you have users and a way to login. Your controllers would more than likely be secured in some way, which works for the internal users of the application. Now you want to add one method which effectively becomes an API, available outside of the application and calls to it will have to be authenticated somehow.
What I would suggest is to split this up. You can create a separate project, which is a WebAPI one, in the same solution. The code which prepares the data can live in a class library you can then reference in both your MVC and WebAPI projects.
Your MVC app can call it and then return a view with that data, the WebAPI calls it and simply returns the data. You can now decide on a way of securing your API, maybe using Identity Server or some other way and you can keep adding things to it, without affecting the UI layer.
Your second option is to make the MVC app use the API when it needs to retrieve data, so both your public clients and UI use the same thing.
Whichever option you use, the idea is to not duplicate anything and at the same time provide the security layers you need.
I'm implementing a REST Web API. I'm using the examples from Adam Freeman's Pro ASP.NET MVC5 as a starting point but adapting it into the Web API way of doing it.
The below is my code:
public class AdminController : ApiController
{
private IUserRepository _repository;
public AdminController(IUserRepository repository)
{
_repository = repository;
}
public ActionResult Index()
{
return View(_repository.Users);
}
}
In the book, AdminController implemented Controller not ApiController, but if I do that then I get errors about there being no parameterless constructor. I need the constructor to take parameters so that I can inject the dependencies. So that's why I changed to ApiController but now it won't recognise View.
What do I need to use instead of View for an ApiController?
I did find this question but the answer was basically "you don't need to use an ApiController here, just use Controller" so that didn't help me.
You are having two different problems. Let's solve them separately.
1. Do I need to use ApiController or Controller?:
Someone already answered this here: Difference between ApiController and Controller in ASP.NET MVC.
The first major difference you will notice is that actions on Web API
controllers do not return views, they return data.
ApiControllers are specialized in returning data. For example, they
take care of transparently serializing the data into the format
requested by the client.
So, if you want to return a View you need to use the simple ol' Controller. The WebApi "way" is like a webservice where you exchange data with another service (returning JSON or XML to that service, not a View). So whenever you want to return a webpage (View) for a user you don't use the Web API.
In other words, the Web API is about returning data to another service (to return a JSON or XML), not to a user.
2. But if I use Controller then I get "parameterless constructor" errors.
Okay, now we've got to your real problem. Don't try to reinvent the wheel and fight with ASP.NET about doing dependency injection! A tool already exists to resolve dependency injection and sort out the "parameterless constructor" error: Ninject.
If you're already using Ninject and still getting that error, you're doing something wrong with Ninject. Try to repeat the installation and configuration steps, and see some tutorials or questions about parameterless error with Ninject use
An API controller is a controller which provides a RESTful response. You cannot return a view from it. Instead of doing that, consider returning a response (values) which forces the client that asks for an action to redirect to another controller (passing arguments if necessary) to return a view.
Your case does not look like you need an API; in this case just try this (change what you inherit):
public class AdminController : Controller
{
private IUserRepository _repository;
public AdminController(IUserRepository repository)
{
_repository = repository;
}
public ActionResult Index()
{
return View(_repository.Users);
}
}
I will try to explain what an API should do anyway. A web API should return just information. An HTTP response about what the action should do.
For example, to create a new customer, an API should have a method (decorated with POST) to get information from a client application (could be anything: web, windows, mobile, windows service, etc.). This information should be processed by the API (or other layers in a possible architecture) and return an HTTP status code, for example 200 - OK if it was fine or 400 - Bad Request if an error happened. So, when I said you should consider returning information, you could just return a DTO object to provide a result.
Both types of project use MVC principles, but they are used in a different context. Take a look at these articles:
Web Api 2.0 Tutorial
Difference between MVC and WEB API
Also take a look at the ASP.NET website about how they work:
ASP.NET WEB API
ASP.NET MVC
Use Controller to render your normal views. ApiController action only return data that is serialized and sent to the client.
But still you want to render view from APIcontroller, then there may be a another way, click on below link for reference :
https://aspguy.wordpress.com/2013/09/10/web-api-and-returning-a-razor-view/
I am looking for a simple way (if it exists) to generate a URL in a service class for a specified controller and action in an ASP.NET MVC 3 web application. I want to do this in the service layer because of needing to encode this URL in a QR code.
This is simple in a View or in a controller because of the UrlHelper available through System.Web.Mvc so I could create the beginning of the URL in the controller action that uses my service class but I was hoping to do it at the point of QR code generation.
Thanks in advance.
A major reason for having distinct layers is separation of concerns. The service layer should not concern itself with request routing.
I would pass the URL into the service layer and have the service layer return the generated QR code.
I understand the separation of concerns but sometimes a developer has to do what a developer has to do!
So here is what I have done:
var Url = new UrlHelper(HttpContext.Current.Request.RequestContext);
var myUrl= Url.RouteUrl("routeName", new { controller="ControllerName", action="Index", area="", otherDictionaryEntries="otherId"});
Regards!