I have been playing with Webapi 2.0 and OData 2.0 for past 2 weeks. I would like to know as to when to use OData routing and Webapi Attribute routing.
Thanks,
Pavan
Web API is a general framework for creating HTTP endpoints (web APIs/REST APIs). You can also use it to create OData endpoints, which is a more specific application of ASP.NET Web API.
So the first question is whether you want to create an OData endpoint or some other type of REST API.
If you are creating an OData endpoint, use OData routing. Otherwise use the "regular" Web API routing
Web API Routing
you can use default routing but if you want to defined your route templates then you can used AtrributeRouting which is using convention-based routing
In this type of routing, you define one or more route templates, which are basically parameterized strings.
When the framework receives a request, it matches the URI against the route template
install following nuget package :
"Install-Package Microsoft.AspNet.WebApi.WebHost"
Add following line in your "WebApiConfig.cs" file
config.MapHttpAttributeRoutes();
create your webapicontroller like following
[Route("api/users")]
public HttpResponseMessage GetUsers(int userId)
{
you can access your web api like this URL:
http://localhost:8080/api/users/
Web API Odata Routing
when you want to use IQueryable instead of IEnumerable then you can use odata
install nuget package for odata
"Microsoft.AspNet.WebApi.OData"
Add following code in your "WebApiConfig.cs" file
var modelBuilder = new ODataConventionModelBuilder();
modelBuilder.EntitySet<ViewTest>("TestOdata");
var model = modelBuilder.GetEdmModel();
config.Routes.MapODataRoute(routeName: "OData", routePrefix: "odata", model: model);
Add following code in your "UsersOdataController.cs" file
public class TestOdataController : OdataController
{
//GET odata/TestOdata
public IQueryable<ViewTest> Get()
{
try
{
return context.View_TestRepository.GetQueryable();
}
catch (Exception ex)
{
throw ex;
}
}
}
ViewTest : view model class with your required columns
View_TestRepository : Repository class
you can access your odata web api by following URL:
"http://localhost:8080/odata/TestOdata"
Related
I'm creating an ASP.NET Core API app, and currently, and when one creates a new project there is a controller named Values, and by default the API opens it when you run. So, I deleted that controller and added a new controller named Intro, and inside it an action named Get. In the Startup.cs file, I have the following lines of code:
app.UseMvc(opt =>
{
opt.MapRoute("Default",
"{controller=Intro}/{action=Get}/{id?}");
});
And my Intro controller looks like this:
[Produces("application/json")]
[Route("api/[controller]")]
[EnableCors("MyCorsPolicy")]
public class IntroController : Controller
{
private readonly ILogger<IntroController> _logger;
public IntroController(ILogger<IntroController> logger)
{
_logger = logger;
}
[HttpGet]
public IActionResult Get()
{
// Partially removed for brevity
}
}
But, again when I run the API, it by default tries to navigate to /api/values, but since I deleted the Values controller, now I get a 404 not found error. If I manually then navigate to /api/intro, I get the result that is provided from my Get action inside the Intro controller. How can I make sure that when the API run (for example through Debug->Start Without Debugging) that it by default gets the Get action from the Intro controller?
You can change it in launchSettings.json file in Properties node. There should be field launchUrl which contains default launching url
With later version of ASP .Net Core, MVC routing is less prominent than it once was, there is general routing now in place which can handle routing of Web APIs, MVC and SignalR amongst other kinds of routes.
If you are using later versions, and not specifically calling app.UseMvc you can do this with the generalised Endpoints configuration:
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute("default", "{controller=Account}/{action=login}/{id?}");
// Create routes for Web API and SignalR here too...
});
Where Account and login are your new default controller and actions. These can be MVC or Web API controller methods.
I have created a .Net Core Web API program. I want to add a single view to it. Under the same project I add a "Views" folder. In the HomeController, where I am routing all my API requests, I created the following:
[HttpGet("view")]
public IActionResult Index()
{
return View();
}
In my Views folder I created a folder "Home" and added "Index.cshtml" to it.
When I launch the API, and navigate to "../view" I get to the return View(); line, but then it returns a 500 Internal Server Error.
This is what I don't like about the "automagical" approach of MVC convention. I have no idea where to link a view to a controller if the convention didn't work.
Update, this probably should have been my first course of action.
I added a new class to Controllers folder, and used the MVC Controller template in VS2015. I then added a view to match, and it still doesn't work automagically.
So for clarity, my project is: ASP.NET Core Web Application(.NET Core) with a Web API template. I have a "Jobs" controller class that was added at the start as 'Values' and I renamed. Then I added an MVC Controller Class named "HomeController" with the only method being "Index". I added a folder named "Views" and a subfolder named "Home", and added an MVC View Page named "Index.cshtml".
I tried to use "return View();" in the Index method, didn't work. I then tried to add [Route("Home/Index")] above the Index method. Either way, the URL will get me to my break point at "return View();" but it will never return the view.
Note : It's a little strange that you want to return a view in a Web API project, a Web API project is supposed to return some data structure, like json using return new JsonResult(your_json_here) for example.
Note 2 : you need the Microsoft.AspNetCore.Mvc framework (which is installed with the Web API template)
Anyway, you have different ways to configure routing in a asp.net core application :
Creating and extending default routes
Example of routing configuration in the Configure method :
app.UseMvc(routes =>
{
// You can add all the routes you need here
// And the default route :
routes.MapRoute(
name: "default_route",
template: "{controller}/{action}/{id?}",
defaults: new { controller = "Home", action = "Index" }
);
});
Using attributes
If you configure routing with attributes, don't forget the controller's one :
Example for the route /index :
[Route("")]
public class HomeController : Controller
{
[HttpGet]
[Route("[action]")]
public IActionResult Index()
{
return View();
}
}
Example for the route /home/index :
[Route("[controller]")]
public class HomeController : Controller
{
[HttpGet]
[Route("[action]")]
public IActionResult Index()
{
return View();
}
}
Example for the route /iputwhatiwant/actionnameiwant :
[Route("iputwhatiwant")]
public class HomeController : Controller
{
[HttpGet]
[Route("actionnameiwant")]
public IActionResult Index()
{
return View();
}
}
My screen of a .NET Core Web API project returning a view :
For more information, the official documentation is well-documented : https://learn.microsoft.com/en-us/aspnet/core/fundamentals/routing
How are you running this webapp, from the Windows commandline?... can you give us the detailed HTTP500 error. It will probably reveal something different than routing errors because that usually gives 404.
[Route("[controller]")]
public class HomeController : Controller
Note the automagical "[controller]" in the Route definition, I think its necessary now
It took me a frustratingly long while to learn the routing convention as it was being developed, but it seems to have normalized out for a few versions. Check out this tutorial documentation on the subject in MVC: Attribute Routing in ASP.NET MVC 5, which is MVC not WebCoreAPI where it is likely based from. If you have a better documentation specific to Web Core API, use that.
This ASP.NET Web Core Build a web API tutorial documentation has some good points about what you seem to be trying to do. Specifically, the section title "Getting to-do items" has this code:
[HttpGet("{id}", Name = "GetTodo")]
public IActionResult GetById(long id)
{
var item = _todoRepository.Find(id);
if (item == null)
{
return NotFound();
}
return new ObjectResult(item);
}
Looking at that with benefit of some measure of MVC routing experience, it looks particularly different from your approach in that the HTTP verb annotation member property value used is a query parameter.
Seeing I am guessing using known inexpertise, still, I think you need to get the attribute routing fixed, and maybe return an ObjectResult instead of a view, as NightOwl888 suggests. The server error might also have much more useful information along with the exception message.
EDIT: Sorry, I may have misunderstood your question. If you are trying to build an app that serves dynamic web pages instead of a WebAPI that serves data object results, this Build an MVC Web App tutorial, similar to the "Build a web API" tutorial I mentioned before might have your app structure problem answer. If you are trying to do both, you should probably start with the MVC Web App structure or use two separate projects.
The (only) way I have got this working is to declare the path as an attribute on the action - in the same way you have done but with the format as below (Controller/Action):
[HttpGet("Home/Index")]
public IActionResult Index()
{
return View();
}
I was missing:
"preserveCompilationContext": true
in the build options of my project.json
I like to know how to configure the odata routing so that I can have
URL/odata/{databaseName}/SalesOrder
example
URL/odata/mydatabase1/SalesOrder
URL/odata/mydatabase2/SalesOrder
And then the controller to be able to retrieve the databaseName token.
I have tried to add
config.MapODataServiceRoute("odata", "databaseName", model: GetModel());
but that does not quite work.
config.MapODataServiceRoute("odata", "{companyId}/odata", model: GetModel());
Above code needed to go in to WebApiConfig and then within your controller
var company = System.Web.HttpContext.Current.Request.RequestContext.RouteData.Values["companyId"];
I have created a backend service using Azure Mobile App. Offline sync works fine with mobile clients using provided SDK. All the controllers that I have used are TableController. Now I want to add a simple Web API 2 controller ApiController, that will not be used by mobile clients.
Here is a simple ApiController that I have added to Controllers folder:
public class SimpleController : ApiController
{
public string Get()
{
return "Hello";
}
}
But the controller is never hit. If I add [MobileAppController] attrebute to the controller, it works but now it asks for additional headers in the request (I guess this headers are sent by client SDK):
{"message":"No API version was specified in the request, this request needs to specify a ZUMO-API-VERSION of '2.0.0'. For more information and supported clients see: http://go.microsoft.com/fwlink/?LinkId=690568#2.0.0"}
But I do not need this additional functionality here - I just want my service to respond to simple GET requests.
Although the guide states that it is not necessary to decorate the class:
Any controller that does not have MobileAppControllerAttribute applied can still be accessed by clients, but it may not be correctly consumed by clients using any Mobile App client SDK.
I can not achieve this. Am I missing something?
Thanks
I have figured out how to use both types of controllers.
Just add a call to config.MapHttpAttributeRoutes(); in your StartUp.ConfigureMobileApp method like this:
public static void ConfigureMobileApp(IAppBuilder app)
{
HttpConfiguration config = new HttpConfiguration();
//For more information on Web API tracing, see http://go.microsoft.com/fwlink/?LinkId=620686
config.EnableSystemDiagnosticsTracing();
config.MapHttpAttributeRoutes(); //Add this line
new MobileAppConfiguration()
.UseDefaultConfiguration()
.ApplyTo(config);
... //rest of the code
}
And then decorate your controller with custom route:
[Route("api/Simple")] //add this
public class SimpleController : ApiController
{
public string Get()
{
return "Hello";
}
}
Assuming you forgot to tick the Web API checkbox (add it to the project) when making a new MVC (5) project, what do you need to do add Web API and get it working?
There are a bunch of migration questions, but none seemed to have the complete and up-to-date steps for adding Web API to an MVC 5 project and it seems to have changed from some of the old answers.
Add Web API to MVC 4
Adding GlobalConfiguration.Configure(WebApiConfig.Register) MVC 4
Update the MVC project
Use Nuget to get the newest Web API.
Project - Right click - Manage Nuget Packages - Search for Web API (Microsoft ASP.NET Web API ...) and install it to your MVC project.
Then you still need to get Web API routing to work.
From Microsoft's Configuring ASP.NET Web API 2
Add WebApiConfig.cs to the App_Start/ folder
using System.Web.Http;
namespace WebApplication1
{
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// TODO: Add any additional configuration code.
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
// WebAPI when dealing with JSON & JavaScript!
// Setup json serialization to serialize classes to camel (std. Json format)
var formatter = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
formatter.SerializerSettings.ContractResolver =
new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver();
}
}
}
If you have an MVC Project it will have Global.asax.cs, add the new routes. Order of the Global.asax.cs routes is critical. Note there are outdated examples which use
WebApiConfig.Register
Add this line to Global.asax.cs:
GlobalConfiguration.Configure(WebApiConfig.Register);
protected void Application_Start()
{
// Default stuff
AreaRegistration.RegisterAllAreas();
// Manually installed WebAPI 2.2 after making an MVC project.
GlobalConfiguration.Configure(WebApiConfig.Register); // NEW way
//WebApiConfig.Register(GlobalConfiguration.Configuration); // DEPRECATED
// Default stuff
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
WebAPI Help
To get the (very) helpful WebAPI help pages, install WebAPI.HelpPage.
See http://channel9.msdn.com/Events/Build/2014/3-644 (~42 minutes in) for what it does. It looks very helpful!
Nuget Console: Install-Package Microsoft.AspNet.WebApi.HelpPage
To verify WebAPI is working:
To the controllers folder -> Add new item -> Web API Controller Class.
public class TestController : ApiController
{
//public TestController() { }
// GET api/<controller>
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
// GET api/<controller>/5
public string Get(int id)
{
return "value";
}
//...
}
Now you can test in IE/FF/Chrome as usual, or in the JavaScript consoles for non-get testing.
(With just the controller in the URL it will call the GET() action in the new Web API Controller, it's automatically mapped to methods/actions depending on the REST e.g. PUT/POST/GET/DELETE. You don't need to call them by action like in MVC)
The URL directly:
http://localhost:PORT/api/CONTROLLERNAME/
Alternatively use jQuery to query the controller.
Run the project, Open the console (F12 in IE) and try run an Ajax query. (Check your PORT & CONTROLLERNAME)
$.get( "http://localhost:PORT/api/CONTROLLERNAME/", function( data ) {
//$( ".result" ).html( data );
alert( "Get data received:" + data);
});
Side note: There are some pros/cons to consider when combining MVC and Web API in a project
WebAPI Help verification:
http://localhost:PORT/help