How an asp.net becomes MVC or WebApi? - c#

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.

Related

MVC5 / WEBAPI 2 routing HomeApiController to /api/home rather than /homeapi

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.

Enable CORS in Umbraco 6 / Web API 2 Instance

I'm a newer developer who has been developing a RESTful API with Web API 2 within an instance of Umbraco 6. After some research on http://www.asp.net/web-api/overview/security/enabling-cross-origin-requests-in-web-api, I added the attribute to my controller as such:
[EnableCors(origins: "http://example.com,http://example.local", headers: "*", methods: "*")] //CORS TESTING
public class PropertiesController : UmbracoApiController
{
//Code Hidden
}
I'm finding that I can go to a site like http://codebeautify.org/jsonvalidate and pull in my JSON through the endpoint URL and validate it even though I didn't allow that host to call my API.
Following the instructions from the asp.net link above, I noticed that my solution doesn't have an "App_Start" folder with a WebApiConfig.CS file, so I was never able to add the config.EnableCors(); code which I think may be the underlying issue? I'm not sure how to continue at this point because to get this far, I just had to add a new Web API Controller Class to '/App_Code' and then inherit UmbracoApiController.
You can create the WebApiConfig.cs if you wish and call it from Global.asax.cs . Or just call EnableCors() wherever you have the config. This is a simple answer with an example https://stackoverflow.com/a/29397652/3520146 .

Web Api and MVC Individual Account

in visual studio 2013 i've created a web api project (selecting also mvc framework in the wizard)
Anyway in the Controllers i've only the AccountController class derived from ApiController
public class AccountController : ApiController
It's possible, in the same project, have a mvc controller and api controller? How can i handle the authentication (signup, login,ecc...) with api controller and mvc controller?
The wizard generate only the apicontroller
you can certainly create a new MVC controller with the same name, as long as your route configurations dontcreate any clashes. The MVC controller will implement Controller rather than ApiController.
As you may expect, you will need to make sure you dont have any namespace clashes either.
For authentication there are separate AuthorizeAttributes you can use. The one in System.Web.Http is for WebAPI and the one for MVC can be found in System.Web.MVC

How to configure Web Api 2 to look for Controllers in a separate project? (just like I used to do in Web Api)

I used to place my controllers into a separate Class Library project in Mvc Web Api. I used to add the following line in my web api project's global.asax to look for controllers in the separate project:
ControllerBuilder.Current.DefaultNamespaces.Add("MyClassLibraryProject.Controllers");
I never had to do any other configuration, except for adding the above line. This has always worked fine for me.
However I am unable to use the above method to do the same in WebApi2. It just doesn't work. The WebApi2 project still tries to find the controllers in its own project's controllers folder.
-- Giving little summary update after 2 months (As I started bounty on this):
I have created a WebApiOne solution, it has 2 projects, the first one is WebApi project, and the second is a class library for controllers. If I add the reference to the controllers class library project into the WebApi project, all works as expected. i.e. if i go to http://mydevdomain.com/api/values i can see the correct output.
I have now create a second project called WebApiTwo, it has 2 projects, the first one is WebApi2 project, and the second is a class library for controllers. If I add the reference to the controllers class library project to the WebApi2 project, it doest NOT work as expected. i.e. if i go to http://mydevdomain.com/api/values i get "No type was found that matches the controller named 'values'."
for the first project i am not doing any custom settings at all, i do NOT have:
ControllerBuilder.Current.DefaultNamespaces.Add("MyClassLibraryProject.Controllers");
in my global.asax, and i have not implemented any custom solutions proposed by StrathWeb in two of his blog posts, as i think its not applicable any more; because all works just by adding the reference of the controller project to the WebApi project.
So i would expect all to work same for WebApi2 ... but its not. Has anyone really tried doing this in WebAPi2 ?
I have just confirmed that this works fine. Things to check:
References: Does your main Web API project reference the external class library?
Routing: Have you set up any routes that might interfere with the external controllers?
Protection Level: Are the controllers in the external library public?
Inheritance: Do the controllers in the external library inherit from ApiController?
Versioning: Are both your Web API project and class library using the same version of the Web API libraries?
If it helps, I can package up my test solution and make it available to you.
Also, as a point to note, you don't need to tell Web API to find the controllers with the line you added to Global.asax, the system finds the controllers automatically provided you have them referenced.
It should work as is. Checklist
Inherit ApiController
End controller name with Controller. E.g. ValuesController
Make sure WebApi project and class library project reference same WebApi assemblies
Try to force routes using attribute routing
Clean the solution, manually remove bin folders and rebuild
Delete Temporary ASP.NET Files folders. WebApi and MVC cache controller lookup result
Call `config.MapHttpAttributeRoutes(); to ensure framework takes attribute routes into consideration
Make sure that the method you are calling is made to handle correct HTTP Verb (if it is a GET web method, you can call via browser URL, if it is POST you have to otherwise craft a web request)
This controller:
[RoutePrefix("MyValues")]
public class AbcController : ApiController
{
[HttpGet]
[Route("Get")]
public string Get()
{
return "Ok!";
}
}
matches this url:
http://localhost/MyValues/Get (note there is no /api/ in route because it wasn't specified in RoutePrefix.
Controller lookup caching:
This is default controller resolver. You will see in the source code that it caches lookup result.
/// <summary>
/// Returns a list of controllers available for the application.
/// </summary>
/// <returns>An <see cref="ICollection{Type}" /> of controllers.</returns>
public override ICollection<Type> GetControllerTypes(IAssembliesResolver assembliesResolver)
{
HttpControllerTypeCacheSerializer serializer = new HttpControllerTypeCacheSerializer();
// First, try reading from the cache on disk
List<Type> matchingTypes = ReadTypesFromCache(TypeCacheName, IsControllerTypePredicate, serializer);
if (matchingTypes != null)
{
return matchingTypes;
}
...
}
Was running into same scenario and #justmara set me on the right path. Here's how to accomplish the force loading of the dependent assemblies from #justmara's answer:
1) Override the DefaultAssembliesResolver class
public class MyNewAssembliesResolver : DefaultAssembliesResolver
{
public override ICollection<Assembly> GetAssemblies()
{
ICollection<Assembly> baseAssemblies = base.GetAssemblies();
List<Assembly> assemblies = new List<Assembly>(baseAssemblies);
var controllersAssembly = Assembly.LoadFrom(#"Path_to_Controller_DLL");
baseAssemblies.Add(controllersAssembly);
return baseAssemblies;
}
}
2) In the configuration section, replace the default with the new implementation
config.Services.Replace(typeof(IAssembliesResolver), new MyNewAssembliesResolver());
I cobbled this syntax together using pointers from this blog:
http://www.strathweb.com/2013/08/customizing-controller-discovery-in-asp-net-web-api/
As others have said, you know if you are running into this issue if you force the controller to load by directly referencing it. Another way is to example the results of CurrentDomain.GetAssemblies() and see if your assembly is in the list.
Also: If you are self-hosting using OWIN components you WILL run into this. When testing keep in mind that the DefaultAssembliesResolver will NOT kick in until the first WebAPI request is submitted (it took me awhile to realize that).
Are you sure that your referenced assembly was loaded BEFORE IAssembliesResolver service called?
Try to insert some dummy code in your application, something like
var a = new MyClassLibraryProject.Controllers.MyClass();
in configuration method (but don`t forget, that compiler can "optimize" this code and totally remove it, if "a" is never used).
I've had similar issue with assembly loading order. Ended up with force loading dependent assemblies on startup.
You need to tell webapi/mvc to load your referrenced assembly. You do that with the compilation/assemblies section in your web.config.
<compilation debug="true" targetFramework="4.5.2">
<assemblies>
<add assembly="XYZ.SomeAssembly" />
</assemblies>
</compilation>
Simple as that. You can do it with code the way #user1821052 suggested, but this web.config version will have the same effect.
Apart from what has been said already:
Make sure you don't have two controllers of the same name in different namespaces.
Just had the case where one controller (foo.UserApiController) should be partially migrated to a new namespace (bar.UserApiController) and URI. The old controller was mapped by convention to /userapi, the new one was attribute-routed via RoutePrefix["api/users"]. The new controller didn't work until I renamed it to bar.UserFooApiController.
When using AttributeRouting it is easily forgettable to decorate your methods with the Route Attribute, especially when you are using the RoutePrefix Attribute on your controller class. It seems like your controller assembly wasn't picked up by the web api pipeline then.
If your class library is built with EF then make sure you have the connection string specified in the App.config for the class library project, AND in the Web.config for your Web API MVC project.

Minimum files needed to deploy webAPI server side

So after a great deal of research I'm starting to enhance our service server stack with a webAPI entry point. Based on this thread, and especially the last post by a member of the Digerati board, we are implementing webAPI services as a facade into our WCF application layer. (Our WCF services are just facades into our Application layer where all of the behavior lives)
My question is this. I downloaded MVC 4 and created a new WebAPI project in my service solution. But wow there was a ton of crap that created in my project that I just am not going to need! For example, all of the image files, the home controller, views and models, etc.
So in stripping this down to be just a service project, what are the minimum files I need to build a functional service project? Our intent is to publish both of the service types (WCF and webAPI) side by side in the same server .. each service call doing the same identical service call and returning the specific DTO for the request. So far it looks like App_Start, Controllers, and the Glabal.asax/web.config entries. I definitely don't need Views, Models, or Images!!!
Any input on what others have done to do a pure service deployment would be of great welcome here.
Same problem here. I've found that article from Shawn Kendrot explaining how to create minimal Web API project. It was written for the beta version of Web API but it seems to be still valid.
Create an empty ASP.NET project.
Add a reference to System.Web.Http and System.Web.Http.WebHost (version 4.0.0.0)
Add a Global.asax file
Register a route in the Global.Application_Start. Something like:
protected void Application_Start(object sender, EventArgs e)
{
GlobalConfiguration.Configuration.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional });
}
Add a controller
public class SampleController : ApiController
{
public string Get(int id)
{
return "Hello";
}
}
Run the project locally with the URL /api/sample/123 and enjoy the outcome:
FYI. I have found that I have had to reference two more .dlls:
System.Net.Http
Newtonsoft.Json

Categories

Resources