I currently have a MVC 3 Web Application with around 50 Views.
Is it somehow possible to provide some kind of API next to my Views so everything still works fine and dandy?
My kinda perfect world idea:
Server is running and every request gets to its view. The user can decide in his get request if he wants the raw data in lets say JSON. Additional to the raw data also the Structure/Names of the Viewmodel will be parsed so the Modelbinder can do his stuff.
or another approach might be to somehow deactivate my Views to have only the API available (again with raw data and structure).
Is this even possible (the modelbinder is kinda a big concern) and maybe even without much effort/trouble to do?
If you don't want to do everything all over again with WebAPI, you can implement some ActionFilterAttribute to change the ActionResult based on some querystring f.i.
Something like this:
public class ResultSwitcherAttribute: ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
if (filterContext.HttpContext.Request["data"] != null && filterContext.HttpContext.Request["data"] == "json")
{
filterContext.Result = new JsonResult
{
Data = (filterContext.Result as ViewResult).Model,
JsonRequestBehavior = JsonRequestBehavior.AllowGet
};
}
}
}
Then, you'll register that either in application_start or per controller/action like this:
[ResultSwitcherAttribute]
public class HomeController : Controller
{
public ActionResult Index()
{
return View(new TestModel()
{
Web = "http://www.mywebpage.com", Name = "Yngve"
});
}
}
When you now access your url with ?data=json you'll get a JSON-representation of the Model, instead of the view.
EDIT: Code sample updated
Consider adding an ASP.NET Web API to your app. It's extremely simple to implement, entailing little more than adding an API controller with methods corresponding to your REST actions. I don't know how one would go about adding this to an MVC 3 app, but I have a recipe for MVC 4 Internet Applications in this stackoverflow question. So, if you're fine with upgrading your project so that it is Web API capable, perhaps to MVC 4, I think it'd represent a good alternative.
To learn ASP.NET Web API, this tutorial is a good place to start.
Related
I have an application developed in ASP.NET Core MVC with a set of controllers for normal view responses and Web API.
I am trying to figure a correct way to wrap all Web API responses with a consistent class.
My first question is what would be a correct approach to wrap the responses coming from Web API controllers. Since I have two controller types, I would need to distinguish between them as the responses should only be wrapped for API controller, and not view controllers.
As I understand there are two choices a middleware or an action filter.
At first I thought the middleware would be the best choice, but then I realized that I would still need to figure out what kind of request is being processed which would add more potential headache with maintenance?
Then I looked at an action filter and it seems that it would be a better choice to plugin the wrapping handling.
For example an action filter can be added to a base controller just for Web API and not controllers handling the views.
So the question is whether the action filters are best approach to achieve this?
I would recommend you to look at result filters for this. Result filters run after a controller action has produced a result, and it allows you to look at that result and then perform some action.
For example, when you return View in a controller action, then what gets returned is a ViewResult which makes it easy to identify results that would cause a Razor view to be rendered.
Within an API controller, you would usually return a ActionResult<T>, some model object directly, or an ObjectResult. The former two will be automatically converted into an ObjectResult as the action gets executed. So you can just look for ObjectResults and then change the result to have some wrapper object instead. This would look something like this:
public class WrapApiResponseResultFilter : IResultFilter
{
public void OnResultExecuting(ResultExecutingContext context)
{
var result = context.Result;
if (result is ObjectResult)
{
// wrap the inner object
var newValue = new WrapperObject(result.Value);
// replace the result
context.Result = new ObjectResult(newValue)
{
// copy the status code
StatusCode = result.StatusCode,
};
}
}
public void OnResultExecuted(ResultExecutedContext context)
{ }
}
I am just trying to figure out what would be the easiest and quickest way to get particular value from WebApi controller.
my web API controller
public IEnumerable<string> Get()
{
return new string[] { fullname,lastname, email};
}
when I try to consume this web API in the angular controller by using the below method
this._httpService.get('/api/user').subscribe(values => {
this.details= values.json() as string[];
});
it returns all the values (fullname,lastname, email). but what I am trying to get here is lastname.
something like this.details.lastname
For clarity, if you are using Angular (not AngularJS), then the code is called a component not a controller.
Which version of Angular are you using? If it is > 4.3, then you don't need the .json() anymore. The mapping is handled for you automatically.
To answer your question ... the "quickest" way would be something like this (assuming Angular v6):
this.http.get<>('/api/user').subscribe(
details => this.lastName = details.lastName
);
Assuming that details is one item, not an array.
But this is definitely not the "best" way.
The best way would be to define an interface for your details and then build a proper client-side service to encapsulate your data access.
I have recently started working on MVC application. However my first plan was to create two separate projects in the same solution. One asp.net MVC web application and second is asp.net WebAPI. So that my Web Application will talk to Web API which in return will send JSON response to application which will be converted to View Model for View.
Workflow Diagram :
As i studied more i got to know that API controller and controller both merged into a single controller class in MVC 5. so here is my question how can i achieve the above workflow in MVC 5.
MVC 5 Workflow Diagram
So here comes the problem for me in MVC 5 or i am unable to understand it completely E.g :
UserModel
public class UserModel
{
Public int UserId {get;set;}
Public string Username {get;set;}
}
UserController
[HttpGet()]
public IActionResult GetUser(int id)
{
// do some work
return View(userObject);
}
View
#model UserModel
<h1>#Model.Username</h1>
but when i call the above method from mobile it will give me the rendered html which is not useful for me so do i need to create another method in the same controller in which will return data in JSON.
[HttpGet()]
public IActionResult ApiGetUser(int id)
{
// do some work
return JSONResponse.. ;
}
Modifying method :
[HttpGet()]
public IActionResult GetUser(int id)
{
// calling api get user method
ApiGetUser(int id); // return json
// do some work to convert json into ModelObject
return View(userObject);
}
And if any one mobile app needs data it can call m APIGetUser Method but in this scenario for me its tedious and no of extra methods will be added in the same class. So my basic question is my understanding towards the flow is wrong or am i missing somethings because if below mentioned workflow is right than i would prefer the first one as its separate WebAPI project and easy to maintain ?
In my opinion both diagram are architecturally correct.
But you should consider SRP and separation of concern this: if MVC controller + WebApi controller are both an entry point to your application, running the same code and returning it in 2 different way, they are actually doing 2 different things isn'it? One serve the view and the other one the json.
Plus if you have to render a view there are naturally some behaviuour that isn't common with your web api (cache or rendering partial view for example).
If you think the same, you should leave aside that in MVC 5 both MVC+WebApi controller are under the same class and split it for the reason above.
Hope it helps!
So I have two separate projects (one Web Api 2 and one MVC) like this diagram:
The MVC has controllers and a service layer. The services from the MVC app call to the web api controllers. For example:
await _service.GetGiftCards("/api/GiftCards/ViewAllByUser", email);
The Web Api controllers have their routes defined like so:
[RoutePrefix("api/giftcards")]
[Route("ViewAllByUser")]
public async Task<List<GiftCard>> GetGiftCardsForUser(string email){}
So to define the endpoint route in the MVC app I simply pass a string like "/api/GiftCards/ViewAllByUser" above.
My question is, is there a better way to sort of "strongly type" the endpoints of the Web Api routes that are defined so I can do something like?:
await _service.GetGiftCards(GiftCardController.ViewAllByUser, email);
I guess at a minimum I could always just store the endpoint strings in a static class like so, so they at least can all be updated in one place:
public static class ApiEndpoints(){
public string GetAllGiftCards = "api/GiftCards/ViewAllByUser";
}
but I'm looking to know if there are better ways or other suggestions. Thanks!
API routes shouldn't specify actions. You want your routes to be logical paths to a record or group of records. Example, in your case the route should look something like this:
GET
api/giftcards/{userID:int:min(1)}
You want to be able to walk up the url basically and get what you would expect. In the case of the example route you would get gift cards based on the user id. If you were to take off the user id page and just call api/giftcards you would expect to get all gift cards by all users. I'm using an ID here but you would do the same with email.
Pleas try with 'ActionName' Attribute on action like this :
[ActionName("SelectAll")]
public IEnumerable<Customer> Get()
{
...
}
calling this action name like:
$("#getdata").click(function () {
var options = {};
options.url = "/api/customer/SelectAll";
options.type = "GET";
...
...
$.ajax(options);
});
note: 'getdata' is id of control which click event will be fired and calling 'api method' and getdata from api
Here's a library that may be what you're looking for.
Although I like static strings so you don't always have to show future developers on your team how to use said library when updates are needed on the clients.
I want to be able to take over the 404 response from web api (iis) when the resource does not exist.
I have done my research and came across only one solution that made this work, but i am not sure how "safe" it is since the "routeTemplate" is just {*url}
This post is kinda to ask for help and explanation.
My App uses MVC and WebAPI... would this template affect MVC as well?
Is there a way to add "api" with {*url} in the template? (to make sure only requests with ".../api/..." get affected)
config.Routes.MapHttpRoute("Error404", "{*url}", new { controller = "Error", action = "Handle404" });
Has anyone come across a cleaner way of doing this and handling 404 in web api?
EDIT 1
The above code DOES affect my MVC routes.
How can i add "api" to "{*url}"?... if tried many different ways and no dice.
Had the exact same issue. After some research and trial and error, I was able to find a working solution.
I went with a RoutePrefix solution and I tried to implement something similar to how the MVC controllers used HandleUnknownAction in a base controller.
With the help from this post: .NET WebAPI Attribute Routing and inheritance to allow for route inheritance, I created a base controller for my web APIs with a HandleUnknownAction method like this:
public abstract class WebApiControllerBase : ApiController {
[Route("{*actionName}")]
[AcceptVerbs("GET", "POST", "PUT", "DELETE")]//Include what ever methods you want to handle
[AllowAnonymous]//So I can use it on authenticated controllers
[ApiExplorerSettings(IgnoreApi = true)]//To hide this method from helpers
public virtual HttpResponseMessage HandleUnknownAction(string actionName) {
var status = HttpStatusCode.NotFound;
//This is custom code to create my response content
//....
var message = status.ToString().FormatCamelCase();
var content = DependencyService
.Get<IResponseEnvelopeFactory>()
.CreateWithOnlyMetadata(status, message);
//....
return Request.CreateResponse(status, content);
}
}
If you don't want to go down the inheritance path, you can always put the method directly into the controller you want to apply the functionality on.
This allows me to use route prefixes that handle custom not found messages that pertain to specific controllers as I have both back-office and public public facing APIs.
If a URL does not apply to an ApiController the default Error controller will handle the not found as usual.