The question title might not be clear but what I want to do is something like this:
This is how I layer out my app
App.Domain
App.Services
App.Web
What I want is, if I request something like /api/OrderProcessor/GetAllOrder it will call method GetAllOrder in App.Services.OrderProcessorService.
The method will return an IList<Order> and i would like it to be serialized into JSON according to a certain format (I'm using ExtJS actually), to maybe something like:
{
success: true,
totalCount: 10,
list: [ { ... }, { ... } ]
}
I can go on and make the Services as Controllers, but I don't want the service layer to be tainted with presentation stuff.
How can I go about making a wrapper controller like this?
I don't want to attach any attributes on the Service class itself, and would probably be nice if I can configure it using IoC, where by maybe later on I want the output be XML or maybe the ability to use a DTO class instead of the original Domain class.
Any idea?
It's sounds like you're trying to make a RESTful service.
Using a RESTful service, the /api/OrderProcessor/GetAllOrders URI would return your JSON objects.
If that's the case, I would use WCF instead of ASP.NET MVC.
To get started with WCF, REST, and JSON, check out the WCF REST Starter Kit Preview 2 on Codeplex. There's a quick example of returning JSON from a WCF service in this blog post I found by Ben Dewey.
Good luck!
You could use something like PostSharp's OnMethodInvocationAspect to intercept every call to your controller method and act as a relay to similarly named methods on a designated proxy object...
Related
My title sums this up pretty well. My first though it to provide a few data formats, one being HTML, which I can provide and consume using the Razor view engine and MVC3 controller actions respectively. Then, maybe provide other data formats through custom view engines. I have never really worked in this area before except for very basic web services, very long ago. What are my options here? What is this Web API I see linked to MVC4?
NOTE: My main HTML app need not operate directly off the API. I would like to write the API first, driven by the requirements of a skeleton HTML client, with a very rudimentary UI, and once the API is bedded down, then write a fully featured UI client using the same services as the API but bypassing the actual data parsing and presentation API components.
I had this very same thought as soon as the first talk of the Web API was around. In short, the Web API is a new product from the MS .NET Web Stack that builds on top of WCF, OData and MVC to provide a uniform means of creating a RESTful Web API. Plenty of resources on that, so go have a Google.
Now onto the question..
The problem is that you can of course make the Web API return HTML, JSON, XML, etc - but the missing piece here is the Views/templating provided by the Razor/ASPX/insertviewenginehere. That's not really the job of an "API".
You could of course write client-side code to call into your Web API and perform the templating/UI client-side with the mass amount of plugins available.
I'm pretty sure the Web API isn't capable of returning templated HTML in the same way an ASP.NET MVC web application can.
So if you want to "re-use" certain portions of your application (repository, domain, etc), it would probably be best to wrap the calls in a facade/service layer of sorts and make both your Web API and seperate ASP.NET MVC web application call into that to reduce code.
All you should end up with is an ASP.NET MVC web application which calls into your domain and builds templated HTML, and an ASP.NET Web API application which calls into your domain and returns various resources (JSON, XML, etc).
If you have a well structured application then this form of abstraction shouldn't be a problem.
I'd suggest developing your application in such a way that you use a single controller to return the initial application assets (html, javascript, etc) to the browser. Create your API / logic in WebAPI endpoint services and access those services via JavaScript. Essentially creating a single page application. Using MVC 4 our controller can return different Views depending on the device (phone, desktop, tablet), but using the same JavaScript all of your clients will be able to access the service.
Good libraries to look into include KnockoutJS, SammyJS , or BackBoneJS
If you do have a requirement to return HTML using the WebAPI e.g. to allow users to
click around and explore your API using the same URL then you can use routing\an html message handler.
public class HtmlMessageHandler : DelegatingHandler
{
private List<string> contentTypes = new List<string> { "text/html", "application/html", "application/xhtml+xml" };
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
if (request.Method == HttpMethod.Get && request.Headers.Accept.Any(h => contentTypes.Contains(h.ToString())))
{
var response = new HttpResponseMessage(HttpStatusCode.Redirect);
var htmlUri = new Uri(String.Format("{0}/html", request.RequestUri.AbsoluteUri));
response.Headers.Location = htmlUri;
return Task.Factory.StartNew<HttpResponseMessage>(() => response);
}
else
{
return base.SendAsync(request, cancellationToken);
}
}
}
For a full example check out:-
https://github.com/arble/WebApiContrib.MessageHandlers.Html
I've played with this idea before. I exposed an API through MVC3 as JSONResult methods on different controllers. I implemented custom security for the API using controller action filters. Then built a very AJAX heavy HTML front-end which consumed the JSON services. It worked quite well and had great performance, as all data transferred for the web app was through AJAX.
Frederik Normen has a good post on Using Razor together with ASP.NET Web API:
http://weblogs.asp.net/fredriknormen/archive/2012/06/28/using-razor-together-with-asp-net-web-api.aspx
One important constraint of a well designed REST service is utilizing "hypermedia as the engine of application state" (HATEOAS - http://en.wikipedia.org/wiki/HATEOAS).
It seems to me that HTML is an excellent choice to support as one of the media formats. This would allow developers and other users to browse and interact with your service without a specially built client. Which in turn would probably result in the faster development of a client to your service. (When it comes to developing actual HTML clients it would make more sense to use a json or xml.) It would also force a development team into a better designed rest service as you will be forced to structure your representations in such a way that facilitates an end users navigation using a browser.
I think it would be smart for any development team to consider taking a similar approach to Frederik's example and create a media type formatter that generates an HTML UI for a rest service based on reflecting on the return type and using conventions (or something similar - given the reflection I would make sure the html media format was only used for exploration by developers. Maybe you only make it accessible in certain environments.).
I'm pretty sure I'll end up doing something like this (if someone hasn't already or if there is not some other feature in the web api that does this. I'm a little new to Web API). Maybe it'll be my first NuGet package. :) If so I'll post back here when it's done.
Creating Html is a job for an Mvc Controller not for Web Api, so if you need something that is able to return both jSon and Html generated with some view engine the best option is a standard Mvc Controller Action methosd. Content Negotiation, that is the format to return, can be achieved with an Action Fiter. I have an action filter that enable the the controller to receive "hints" from the client on the format to return. The client can ask to return a view with a specific name, or jSon. The hint is sent either in the query string or in an hidden field (in case the request comes from a form submit). The code is below:
public class AcceptViewHintAttribute : ActionFilterAttribute
{
private JsonRequestBehavior jsBehavior;
public AcceptViewHintAttribute(JsonRequestBehavior jsBehavior = JsonRequestBehavior.DenyGet)
{
this.jsBehavior = jsBehavior;
}
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
string hint = filterContext.RequestContext.HttpContext.Request.Params["ViewHint"];
if (hint == null) hint = filterContext.RequestContext.RouteData.Values["ViewHint"] as string;
if (!string.IsNullOrWhiteSpace(hint) && hint.Length<=100 && new Regex(#"^\w+$").IsMatch(hint) )
{
ViewResultBase res = filterContext.Result as ViewResultBase;
if (res != null)
{
if (hint == "json")
{
JsonResult jr = new JsonResult();
jr.Data = res.ViewData.Model;
jr.JsonRequestBehavior = jsBehavior;
filterContext.Result = jr;
}
else
{
res.ViewName = hint;
}
}
}
base.OnActionExecuted(filterContext);
}
}
Now that it's been a little while through the Beta, MS just released the Release Candidate version of MVC4/VS2012/etc. Speaking to the navigation/help pages (mentioned by some other posters), they've added a new IApiExplorer class. I was able to put together a self-documenting help page that picks up all of my ApiControllers automatically and uses the comments I've already put inline to document them.
My recommendation, architecture-wise, as others have said as well, would be to abstract your application into something like "MVCS" (Model, View, Controller, Services), which you may know as something else. What I did was separate my models into a separate class library, then separated my services into another library. From there, I use dependency injection with Ninject/Ninject MVC3 to hook my implementations up as needed, and simply use the interfaces to grab the data I need. Once I have my data (which is of course represented by my models), I do whatever is needed to adjust it for presentation, and send it back to the client.
Coming from MVC3, I have one project that I ported to MVC4, which uses the "traditional" Razor markup and such, and a new project that will be a single page AJAX application using Backbone + Marionette and some other things sprinkled in. So far, the experience has been really great, it's super easy to use. I found some good tutorials on Backbone + Marionette here, although they can be a bit convoluted, and require a bit of digging through documentation to put it all together, it's easy once you get the hang of it:
Basic intro to Backbone.js: http://arturadib.com/hello-backbonejs/docs/1.html
Use cases for Marionette views (I found this useful when deciding how to create views for my complex models): https://github.com/derickbailey/backbone.marionette/wiki/Use-cases-for-the-different-views
I'll try to make this as concise as possible.
Webpage contains a table that allows for filtering and sorting
Changes to filtering and sorting should be reflected in the URL so the user can bookmark or share filtered views.
The question is: What is an effective convention of allowing all of the sort and filter syntax to be part of the URL and easily interpret/use it on the server without having to write a bunch of custom code that interprets it?
I've been doing some research and I came across the OData URI conventions and I like the way they do things.
http://www.odata.org/developers/protocols/uri-conventions
More research shows the the MVC 4 Web API allows for use of that convention by returning an IQueryable. This looks fantastic except for one part... I'm not implementing a RESTful API at this point and that's all it seems to work with. So how can I use something like OData and still return a View or PartialView? Is there something that will parse the OData URI convention into a C# object?
If anyone has any insights into this problem or suggestions, I'm all ears.
As for the url convention part of your question, I think you have answered your own question with OData. As for getting this data into a C# object I would use the following approach:
Use an action filter to interperet the url parameters and parse them into a c# object.
In your action filter add the url parameters to the route data and the c# object will be available in your action.
ASP.NET MVC Pass object from Custom Action Filter to Action
Take a look at the Telerik MVC grid, they use a GridAction action filter that does pretty much what you are asking.
I would look at custom model binding. A good overview can be found here: http://weblogs.asp.net/nmarun/archive/2010/02/25/asp-net-mvc-model-binding.aspx
It's typically used for POST requests with forms but there's no reason why you can't use it for GET requests too.
Basically, your approach should be to:
Create a new Model class with your filter/sorting parameters as properties:
public class TableParameters {
public string TableFilter { get; set; }
}
In your Controller's Action, add the model as a parameter
public ActionResult TableAction(TableParameters parameters) { /* Action logic */ }
Set your parameters in the URL by saying:
/Controller/TableAction?TableFilter=[your-filter-string]
The parameters object in your action will have the property populated with the value from the query string.
I am writing an area for administering several subsites, almost all of the functionality will be the same across each site (add/edit/remove pages etc) and my repository on instantiation takes the SiteIdentity so all the data access methods are agnostic in relation to this. The problem I have at the moment is trying to make my action methods also agnostic.
The URL pattern I want to use is along the lines of:
"ExternalSite/{identity}/{controller}/{action}/{id}"
A naive approach is to have each action take the identity parameter, but this means having to pass this in to my repository on each action as well as include it in the ViewData for a couple of UI elements. I'd much rather have this something that happens once in the controller, such as in its constructor.
What is the best way to do this? Currently the best I can come up with is trying to find and cast identity from the RouteData dictionary but part of me feels like there should be a more elegant solution.
It sounds like you want to use OnActionExecuting or a Custom ModelBinder to do that logic each time you have a specific parameter name (also known as a RouteData dictionary key).
Creating a custom modelbinder in ASP.NET MVC
Creating an OnActionExecuting method in ASP.NET MVC, Doing Serverside tracking in ASP.NET MVC
You have access to your route values in Request.RequestContext.RouteData, so you can make base controller and public property SiteIdentity, in such case you can access it from all actions in all inherited controllers.
I am trying to develop a RESTful Web service as an ASP.NET MVC 3 Web Application.
(I know, I should use the right tool for the job, which in this case means I should use WCF. But WCF has too many abstraction layers and is thus too big to fit inside my head. It would be cool for a research project, but I am trying to do my job. Besides I previously tried it, and now I am of the opinion that, despite its big promises, WCF sucks big time.)
Anyway, what I want to do is simple: I want my Web service to return its results as either XML or JSON, depending on the type specified in the HTTP request (by, default, JSON). How do I do that?
A Json action result already exists. MvcContrib has an XML action result you can return, or you could just use Content (xmlContent, "text/xml") as your action result.
You can query the accept header to determine which action result you would like to return. As long as your action method returns type ActionResult, it doesn't matter which type it returns.
That said, once you prove the overall concept, there are better ways to structure what you're trying to do.
A quick solution is to create an optional parameter on your Controller method, and return the view as the appropriate format.
public ActionResult GetFormattedResults(string format)
{
var data = GetResults();
ActionResult result = new JsonResult(data);
switch(format.ToLower())
{
case "xml":
result = new XmlResult(data); // this class doesn't exist in MVC3 you will need to roll your own
case "html":
result = new View(data);
}
return result;
}
You could also wrap the formatting functionality into an ActionFilter so you can reuse the functionality across controller methods.
So I've recd. a requirement to create an API to access our application. Not all controller actions are covered by the API (maybe 50%).
I figure I can either use the same project, check the http headers for each request and respond with either xml, JSON or html as required (much like rails).
OR
Create a new ASP.NET MVC application, deploy # api.myapp.com and use it exclusively for API access.
I assume I could write a base controller for the first option to handle 99% of the work. The issue with the first option is we don't need (or want) API functionality for at least 1/2 of controller actions (and prob. never will).
In the second option I have a duplicate of some controllers, but the good news is most/all? my controller actions are only a couple lines of code. Typically:
Whatever whatever = new Whatever(....);
repository.Save(whatever);
Anyway, what do the stack overflowers think?
It seems that you want to create something like REST service. Please have a look at this post of Phil Haack.
Yes, I'm sure you can put it in the same project. But it will be better to separate them in some way (using areas from MvcContrib or move controllers of api and web application to separate assemblies like this done in SharpArchitecture. If your controllers duplicate a lot of code you may create generic controller like:
public class ControllerBase<T, Service> : Controller
where Service : IService<T>
{
public Service service { get; set; }
public ActionResult Save(int id)
{
var item = service.Get(id);
if (TryUpdateModel<T>(item))
{
service.Save(item);
return View("Success");
}
return View("Error", item);
}
}
Hope this helps.
I think I'd put in the same project, but segregate it using separate routes.
API: http://example.com/api/widget/list
App: http://example.com/widget/list
You could then reuse as much code as possible -- push the data selection and other code into your BLL, for instance. Keeping it in the same project will make it easier to use your API code via AJAX from the client.
I think putting the same code in 2 different projects is asking for trouble in the long run.
Put it all in the same project.
If you need some seperation between regular vs API requests you can use seperate routes.
You can then make a private function that does the action and just have the public facing one decide to render in html or JSON/XML