We're setting up a bunch of json web services in ASP.NET which is served as .ashx (custom handlers) files. An example would be:
/mobile/json.ashx
We'd like to implement some form of versioning as well as to not break apps which has not upgraded. So we led down this path:
/mobile/json.ashx?v=1.0
Now, of course we have have a switch statement in our custom handlers to manage the differences between api version but this doesn't sound like a very maintainable solution to me.
What are the best practises for this kind of set up and what options are available for version control?
Thanks
Placing the version in the query parameters (that is, after the ?) suggests to the user that each endpoint is individually versioned. I would avoid this.
If your web service is structured such that there are larger logical units that are being individually versioned, then I would go with something like this:
/api1/1.0/some/endpoint
/api1/1.1/some/endpoint
/api2/1.0/some/other/endpoint
/api2/2.0/some/other/endpoint
...
The version portion of the path comes directly after the thing which is being versioned. This suggests to the user that everything underneath /api1/1.1/ is version 1.1 of API 1 and everything underneath /api2/2.0/ is version 2.0 of API 2.
If someone entirely omits the version portion of the path, the latest version should be implied. So /api2/some/other/endpoint would map to, say, /api2/2.0/some/other/endpoint.
If you're using ASP.NET MVC, all of this can be accomplished very easy using route configuration in the RegisterRoutes method in Global.asax.cs. For example:
routes.MapRoute("api1/1.1", "api1/1.1/some/endpoint",
new { controller = "Api1_1_1", action = "SomeEndpoint" });
where you have a controller class Api1_1_1 with method SomeEndpoint.
Related
I am trying to figure out how to possibly configure the use of different Service Containers for different routes/endpoints in a ASP.NET Core (.NET 5) application.
The background is that we have an application on ASP.NET 4.x that allows for plugins to register their own routes/endpoints (under configurable prefixes - that is also something I need to figure out in ASP.NET Core) - each such plugin gets its own Castle Windsor container where it can register services and other things with services we pre-register in that container. This container is also used to activate any ASP.NET WebApi controllers for that particular plugin.
We have done this by building some custom routing on top of ASP.NET 4 WebAPI/MVC where the route has information about which context it originates from (The core Application or a Plugin) as well as automatically prepending the prefix.
However, ASP.NET Core WebAPI/MVC has changed allot of things and I can't quite figure out how to get to the same result.
Because this is driven by plugins, it doesn't have to be done on a PER route basis obviously, instead PER plugin is good enough (Which would be a group of routes under the same prefix), so I have been trying to figure out of any of these provided a viable path for me:
Application Parts
Feature Providers (that container application parts)
Controller activators
I did try out a combination of all the above where a ApplicationPart would return custom implementation of types, there by letting us carry extra info about the controller to the IControllerActivator. However ASP.NET Core requires RuntimeType's rather than just any "TypeInfo" implementation.
I had a similar question and ran across this blog post which provides an example of using different IServiceCollections for different route prefixes. I think you can adapt it to get what you want.
Apparently the author also published the code in the WebAPIContrib.Core library (nuget package here).
I have a Windows UWP client application that needs to call a REST API hosted by my ASP.NET service. To generate my client proxy I use the following Visual Studio option...
Right click project -> Add -> REST API Client...
I provide the URL of the swagger endpoint and it generates the expected client code. But the downside is it generates all the classes even though in my case I have a shared class library that has all the server side classes defined. This is a pain because the generated classes do not respect the inheritance of my class hierarchy and flattens everything into non-inherited classes.
Is it possible to get AutoRest to reuse an existing .NET library for classes instead of always generating new classes? This was an option when I used the WCF client proxy generator.
It seems like Add REST API client doesn't have advanced setting for reusing. But Add REST API client has two ways for loading metadata file, swagger URL and existing metadata file. By testing on my site, it should be able to update an existing metadata file and to remove or adjust the nodes that you don't want be generated. And then load the updated existing metadata when adding REST API client.
The classes generated may be determined by the metadata json file and the host value. You may also try to submit a request here to see if swagger team can keep the hierarchy when generating the meta file. Or you may need to manual create the proxy to reuse the libraries.
I think it would be fair to describe the "REST API Client" generation tool in Visual Studio as "spartan".
This answer may be too late to help you, or there may be reasons why you can't use a different tool, but in the hope of benefiting you and/or future readers I'll detail how I achieved generating a REST client in NSwagStudio which reuses my existing classes and enums. (NSwagStudio is free and open source, and I have no affiliation).
On the left hand pane, we select our input. Besides the expected Swagger feeds there are some interesting options such as "Web API via reflection" which "uses .NET reflection to analyze ASP.NET Web API or ASP.NET Core controllers" - this is the option I used but my screenshot shows the default Swagger input.
On the right hand pane, click "CSharp Client" and switch to the "CSharp Client" tab.
The magic bullet is to untick "Generate DTO types":
This will cause it to generate only the client, so you can reuse your existing DTOs.
You'll want to specify a namespace for the client, and optionally one or more namespaces which will be added to the generated C# file as using directives. For example, if you want your client to be in the namespace MyNamespace and your model classes are in SomeOtherNamespace you'd enter the following:
It's well worth having a play with the options. A few quick notes about some of the defaults and why I'm happy with them:
The HttpClient is injected and you control the lifecycle (which seems to me a good thing)
A BaseUrl property is defined. I haven't tested this yet but I'm hopeful from looking at the generated code that this will allow me to safely spin up multiple instances of the client class to talk to multiple servers which share the same API
The JsonSerializerSettings property is protected, but can be configured via the UpdateJsonSerializerSettings partial method
I've saved my settings from the File menu and added the .nswag file to source control, so that I can easily regenerate the client in future if necessary.
I am transitioning to using Areas in a project, and each time I make a new one I have to change a few things to make it fit in with how I'd like things to work. The changes involve:
Removing one of the folders that gets created
Modifying the web.config file slightly
Adding a new file or two with some defaults
Modifying the AreaRegistration file slightly
I would rather not have to do these same things every time I create a new area because I'm afraid that the convention will be forgotten and something will get messed up. Is there a way to modify the defaults for New > Area? Or perhaps would it be possible to make a new file template that does what I'd like?
I am transitioning to using Areas in a project
I have been doing something similar for a few months now, but starting with an old WebForms project, adding MVC components via VS 2013's Add -> New Scaffolded Item... feature, in order to leverage MVC's structure and routing, on the server side. I have also been incorporating WebAPI and SignalR on the server side. I am definitely still a beginner, but being maybe a little further along in a similar process, here some of my thoughts and questions about what you want to achieve:
Removing one of the folders that gets created
Modifying the web.config file slightly
Adding a new file or two with some defaults
What environment are you developing in? For instance, if you're using VS 2013's scaffolding you can most likely modify the T4 templates to prevent or redirect the creation of folders, classes, and such. Here is a post addressing where you might find those templates, and here is just one of many intros out there for T4. The path to the templates on your machine will vary based on the VS version. By modifying or creating new templates you should be able to accomplish all 3 points above relatively easy. If you are working in such an environment I will try to expound on exactly how you might go about modifying the out of the box templates (there are probably already plenty of posts that you could refer to which would do a better job though).
Modifying the AreaRegistration file slightly
If you are working with MVC 5, or later, I would recommend using attribute routing. This seems more standard when working within the API paradigm (inheritting from ApiController instead of Controller), but I have found extending this to traditional MVC controllers to be very useful.
Assuming MVC 5, I would recommend modifying AppStart\RouteConfig.cs's RegisterRoutes() method, to enable attribute routing and then add a catch-all route such as:
routes.MapMvcAttributeRoutes();
routes.MapRoute(
"NotFound",
"{*url}",
new {
controller = "Error",
action = "Index"
});
At that point I would delete the xAreaRegistration.cs files, and remove the call to RegisterAllAreas() from Global.asax, but you don't have to go that far. Then I decorate my controllers' classes (wherever they live) and their methods, with attributes as needed. Using attribute routing I've been able to free myself from the traditional MVC conventions. I can still fall back to them, but I can then place my controllers anywhere in my project, and easily define their actions' routes.
That being said, you should probably follow some organizational standards for groups of similar routes, so that as the project grows you don't find yourself wasting a lot of time searching for all controllers/actions matching some set of routes.
Here's a simple example of how this actually translates from URI into method call:
If I had Controller ctl with action act, logically in Area ar, the URI being http://localhost/ar/ctl/a/1, would be routed to MyControllerNameDoesNotMatter.Index(1), below, by using attribute decoration such as:
[RouteArea("ar")]
[RoutePrefix("ctl")]
public class MyControllerNameDoesNotMatter : Controller {
...
[Route("a/{optionalParamDefaultsToNegativeOne=-1}")]
public ActionResult Index(int optionalParamDefaultsToNegativeOne) {
...
}
}
This way of looking at Area is more logical than physical, in that the MyControllerNameDoesNotMatter.cs file does not have to be in the Area\ar\Controllers folder. Since adopting this I have actually drifted away from using the Area scaffolding, other than to lay out application modules at a very high level - think sub-application that could be a stand alone SPA.
I have tried to make the "catch-all" route attribute based, and remove it from RouteConfig.cs, but I have not been able to do this successfully. The issue is route precedence. It works fine as a catch-all for invalid routes. But for a valid route, multiple (2) routes end up being matched because the two attribute routes have the same order of precedence. Whereas, with the catch-all defined in RouteConfig.cs, after registering all attribute routes, the attribute route takes precedence. I have found mixed answers that attempt to address this issue. There seems to have been a Number or Order parameter for the Route attribute at some point, but I have had no luck with that. This seems to be an unresolved issue. Just one of many SO questions, which have gone unanswered.
Edited to account for mvc4 tag
I had not seen the mvc4 tag prior to posting. There are nuget packages available that will achieve much of the same functionality, such as scaffolding and attribute routing for earlier versions of MVC.
So I am reading about building MVC3 projects and there is one thing that seriously bugs me. The folder structure of the project in no way corresponds to the path of the HTTP request. There is a bunch of things I like and would want to use, but having a flat folder structure is not one of them.
Why is this a problem? Well, I see it becoming a problem when building a site with a heavy mix of content pages and various forms/dynamic pages (most of our sites are like that), which would typically be done by different people. It seem it would be too complicated for client-side developers to follow routing rules of dynamic pages and/or creating new ones.
What I would like to understand is if there is way to configure MVC3 application in such a way that:
it follows directory structure for finding controllers without explicit route map for each one
views live in the same folder as corresponding controller
routing magic still works for actions and parameters
For instance I'd like to have a request /fus/ro/dah/ to try to find DahController in the \webroot\fus\ro\dah\ folder and execute its Index action. If not found it would look for RoController with Dah action in the \webroot\fus\ro\ folder, etc.
It is entirely possible that MVC was not meant to be working this way at all and I am just trying to force a square peg into a round hole.
UPDATE:
Looks like I can drop a view file into the desired folder structure, and it will be executed. However layout would not work apparently because it is expecting a controller. Does this mean I have to create a controller for pure content pages? That is a pretty crappy design...
UPDATE 2:
Main issue right now is that creating "fus" folder means that MVC will not even attempt to look for FusController... not under "fus" folder, nor anywhere else. Is it possible to get around that?
For instance I'd like to have a request /fus/ro/dah/ to try to find
DahController in the \webroot\fus\ro\dah\ folder and execute its Index
action. If not found it would look for RoController with Dah action in
the \webroot\fus\ro\ folder, etc.
MVC is not designed for a particular need like this, it is a general framework for building applications using model-view-controller pattern.
If you can't bend the application for the framework you can bend the framework for the application and honestly MVC is very customizable. [As a proof, in the current project (migration from ASP to MVC) that I'm working we have models as xml and no classes also we are using XSLTs for rendering. With a little work we have created custom components like custom view engine, custom validation provider, custom model binder... to make the framework best fit for the application and it does]
MVC is not designed and not forces to use it as it is and you can customize/extend as much you want. In your case you may have to create a
custom controller factory (because you want to customize the way in which the controller is seleced),
custom view engine (because you want to customize where the view is placed)
and may be others.
For custom controller factory you have to extend the DefaultControllerFactory class. There are lot of articles you can find through Google that explains about how to create custom controller factories.
Depending upon the view engine you are using you have to extend the respective one. For ex. if you are using web forms then you have to extend the WebFormsViewEngine and it razor then RazorViewEngine.
For more info. check this link
http://codeclimber.net.nz/archive/2009/04/08/13-asp.net-mvc-extensibility-points-you-have-to-know.aspx
you can mixup Asp.net and Asp.net MVC. as LukLed said, MVC is convention over configuration pattern. if you follow the convention. you dont need to configure. you can check this link for mixing up the asp.net content with MVC3
Mixing Asp.net and Razor
I believe ASP.NET MVC is not meant to be used that way. While you can configure MVC to do it, it is better to keep standard /controller/action/parameters URL format. If you have complex website with many different functionalities, areas may be helpful http://msdn.microsoft.com/en-us/library/ee671793.aspx. Every area get its own set of controllers, models and views, so teams working on different parts of website won't disturb each other.
While it may sound convenient, that framework first searches for DahController and executes Index action, then searches for another one, I find it bad idea. URLs should be clearly defined and Fus controller with Ro action shouldn't just stop working, because someone created RoController with Index action.
Look into using Areas as well. I think that helped me get over my folder structure issues with MVC honestly. So i could use the base folder as my Home details, then i could have a 'Admin' area which was a separate folder, things like that.
How "regular ASP.net" do you want it to be? If you want to do "legacy" ASP.Net Web Forms mixed in with MVC, you certainly can - re: mixing MVC with "file based aspx" - aka "hybrid". At the end of the day, it's all ASP.Net.
This is a standard MVC Application generated by Visual Studio. I've added a folder somedirectory where I want to use the legacy folder/file.ext paradigm and have a default.aspx Web Forms file:
Can I navigate to it via http://foo.com/somedirectory? Yes.
Can I use "pretty urls" too? Yes
Vanilla Global.asax generated by VS, just added MapPageRoute:
....
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
//using "pretty urls" - ordering your routes matter.
routes.MapPageRoute("theWebForm", "legacy", "~/somedirectory/default.aspx");
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
so now I can navigate to it via http://foo.com/legacy
Just check the order of your routes, and perhaps plan on your naming conventions so you don't have "collisions"...
Hth....
I'm in the process of trying out a few things with MVC whilst designing a system and wanted to try and see if I could use the concept of Controllers outside of the MVC framework. When I say outside, I mean within my own C# service as opposed to a web-site.
I started a simple console application to test the theory and it was simple enough to change the profile to a non-client profile, add in System.Web.Mvc, create a controller and have it return a JsonResult. The ease of which this got set up pleased me as that is half the work done if I want a service to respond with JSON.
The next step is to set up a Http Server class, and I would love it if I could leverage the other part of the framework which will map incoming requests to my controllers. Unfortunately, this is the part where I am lost and I have no idea what code goes on behind to arrive at a particular controller's function with the parameters all in place.
Has anyone got an idea on how to accomplish this, or a resource to look at?
In short: I'd like to leverage the use of Controllers in my own service, running it's own HTTP Server.
You can use the design pattern without using the framework - what I mean is, you can apply the model view controller pattern wherever you believe it solves the problem - if you think that you can replace "view" with "service", you could apply some of the concepts...
http://msdn.microsoft.com/en-us/library/ff649643.aspx
However, there are other patterns that may lend themselves better to services, although if we are talking specifically about a JSON service, then just using the ASP.NET MVC framework as it is would work well (rather than trying to re-write it).
Are you not trying to reinvent the wheel?
If returning JSON is one of your main purpose then WCF fulfills your need. Having WCF with you you are free to host it in IIS. This serves your second purpose having its own HTTP server.
You are trying to achieve some kind of routing where based on URL your different actions will be called. Isn't it similar to having a WCF service with different methods and client is calling each of them with different URL?
Trying controller concept in a non web application seems to be innovative, however in your case it looks like over-engineering.
The basic MVC pattern isn't all the difficult to replicate. I would seriously consider writing your own, rather than trying to shoehorn the MVC classes into your app.
Simon
If it helps you, the entire ASP.Net MVC Framework is open source, you can download it all from http://aspnet.codeplex.com/ . You can use the libraries here to view how the Framework is doing things behind the scenes and adapt things for your own use as appropriate.