I added the AspNet.WebAPI to my existing MVC project with help from this post:
How to add Web API to an existing ASP.NET MVC (5) Web Application project?
It basically adds the following controller:
public class APIController : ApiController
{
// GET api/<controller>
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
...
And this in the App_Start:
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();
}
}
}
This works, but for just for mysite/api/API
How do I expand this to work with the rest of my existing controllers (for example mysite/api/CLIENTs)?
From looking at the code, it seems it should just work. I even tried putting "Get" functions in the other controllers but no luck. Actually I don't know why /API works--is it reading the file name of the controller?
So basically, I am looking for advice on where to go next--do I put code in each individual controller, or put many calls in my existing "APIController", or neither.
The controller it added is just an example of a WebAPI controller. You can add more. For example:
public class ClientsController : ApiController
{
public IEnumerable<Client> Get()
{
// return a collection of clients
}
// etc.
}
Since they inherit from different base classes, you'll need to keep your MVC controllers and API controllers separate. So just add API controllers for your API methods.
Related
i am new to webapi and MVC in general. If I wanted to group my service URLs like this
/api/account/create
/api/account/login
/api/account/resetpass
Am I able to put all 3 method calls in the same controller file and somehow map a particular request to the right method?
Create a Controller named Account and Create 3 [GET, POST, PUT, DELETE] method and name them create , login ,resetpass.
By Default, this is the routing for MVC / API(Id can be optional)
route Template: "api/{controller}/{id}",
Example :
public class AccountController : ApiController
{
[HttpPost]
public string Create()
{
// CODE
}
[HttpPost] // or [HttpGet]
public string Login ()
{
// CODE
}
[HttpPost]
public string Resetpass()
{
// CODE
}
}
if you had trouble calling them, try to give them a specific route :
[HttpGet("GetSubject/{subject}")]
public int GetSubjectId(String subject)
{
//CODE
}
Please if you get any error or misunderstanding, don't hesitate to post a comment
I am developing a web application using ASP.NET MVC Core. Everything works perfect on my local machine but whenever I deploy to Azure the Ajax calls always get a 404 Not Found.
Here's a snippet of one controller method:
[HttpGet]
public JsonResult GetPublicHolidays()
{
var events = adminService.GetPublicHolidays();
return new JsonResult(events);
}
And here's the Ajax call:
$.getJSON('#Url.Action("GetPublicHolidays","Admin")',
By default, the URL to an action in an ASP.NET Controller is not the name of the method. There's a lot going on by convention in ASP.NET.
As an example, this is a default ASP.NET Core API controller:
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
// GET api/values
[HttpGet]
public ActionResult<IEnumerable<string>> Get()
{
return new string[] { "value1", "value2" };
}
}
As you can see in the comment, the route is <baseUrl>/api/values. This route is comprised of the base URL, the api prefix and the name of the controller. Because you add a HttpGetAttribute, ASP.NET knows that is the Get method.
So, considering this controller:
public class RandomController : ControllerBase
{
[HttpGet]
public ActionResult<IEnumerable<string>> WhateverWeirdMethodName()
{
return new string[] { "value1", "value2" };
}
}
The URL for the GET request would be <baseUrl>/api/random
I would like to register API Endpoints in ASP.NET by just adding few methods in ApiController. A new method there means a new API.
In a random example below:
public class ProductController : ApiController
needs to serve the following Endpoints:
/
/price
/price/discount
Problem here is all endpoints are having a GET request to /, and result in same output as /.
Reference URL and Service Contract
You can place Route annotation at method for which you want to use custom route.
public class CustomersController : ApiController
{
// this will be called on GET /Customers or api/Customers can't remember what default
//config is
public List<Customer> GetCustomers()
{
...
}
// this will be called on GET /My/Route/Customers
[HttpGet, Route("My/Route/Customers)]
public List<Customer> GetCustomersFromMyRoute()
{
...
}
}
Hi I've 2 different get methods with the below signature and my routing is as follows:
[ActionName("Data")]
public Dictionary<int, string> GetData(int ID)
{
}
[ActionName("Name")]
public Dictionary<int, string> GetName(int ID)
{
}
var route = routes.MapRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
But api/{controller}/Data/9 and api/{controller}/Name/10 are both calling the first method GetData.
Can someone please guide me to fix this.
You will have to decorate your controllerclass with the [RoutePrefix("api/ControllerName")] as well as do the following:
[Route("Data")]
public Dictionary<int, string> GetData(int ID)
{
}
[Route("Name")]
public Dictionary<int, string> GetName(int ID)
{
}
var route = routes.MapRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
You can get a little more fancy with the Route attribute.
[Route("Name/{ThisIsMyIdVariableName}"), HttpGet]
public HttpResponseMessage GetName(int ThisIsMyIdVariableName) { /*code here*/ }
Now you can keep the idea of a pretty url without having to use routes.MapRoute and can call the url like domain.com/Name/19. You can use multiple variable names wrapped with {} in the route and keep your urls pretty and restful when passing multiple variables.
This approach is also very useful if you have the need to version your api controller.
I know this should be a comment instead of an answer, but I don't have the required reputation to comment yet, and I'd like to help. Are both of the above methods returning data based on their id (PK) value? The reason both methods are calling the first method in your Web API server is because they're both appending the same URL extension to the server. A quick and easy way to differentiate these methods could be to change one of the 2 to accept a string that you could then convert back to an int. For instance:
//api/Customer/5
public Dictionary<int, string> GetData(int ID)
{
}
//api/Customer?CustID={custID]
public Dictionary<int, string> GetName(string custID)
{
//convert string to int and continue code
}
This might not be best practice, but this is what I've done in the past when needing to differentiate between GET/POST methods in my web api server. For deserializing, you could use a class like JsonConvert if you're using Json, etc. Then your calls to your controller will add the appropriate URL extensions as defined in the comments I left above the methods. Let me know if you'd like additional explanation.
I am creating an ASP.NET MVC3 restful web service to allow reports to be uploaded from a set of servers. When a new report is created, I want the client app to do a PUT to
http://MyApp/Servers/[ServerName]/Reports/[ReportTime]
passing the content of the report as XML in the body of the request.
My question is: how do I access the content of the report in my controller? I would imagine that it is available somewhere in the HttpContext.Request object but I am reluctant to access that from my controller as it is not possible(?) to unit test that. Is it possible to tweak the routing to allow the content to be passed as one or more parameters into the controller method? The outcome needs to be RESTful, i.e. it has to PUT or POST to a URL like the one above.
Currently my routing is:
routes.MapRoute(
"SaveReport",
"Servers/{serverName}/Reports/{reportTime",
new { controller = "Reports", action = "Put" },
new { httpMethod = new HttpMethodConstraint("PUT") });
Is there any way to modify this to pass content from the HTTP request body into the controller method?
The controller method is currently:
public class ReportsController : Controller
{
[HttpPut]
public ActionResult Put(string serverName, string reportTime)
{
// Code here to decode and save the report
}
}
The object I am trying to PUT to the URL is:
public class Report
{
public int SuccessCount { get; set; }
public int FailureOneCount { get; set; }
public int FailureTwoCount { get; set; }
// Other stuff
}
This question looks similar but doesn't have any answer.
Thanks in advance
Seems like you just need to use the standard ASP.NET MVC model binding capability with the slight wrinkle that you would doing an HTTP PUT instead of the more common HTTP POST. This article series has some good samples to see how model binding is used.
Your controller code would then look like:
public class ReportsController : Controller
{
[HttpPut]
public ActionResult Put(Report report, string serverName, string reportTime)
{
if (ModelState.IsValid)
{
// Do biz logic and return appropriate view
}
else
{
// Return invalid request handling "view"
}
}
}
EDIT: ====================>>>
Jon added this code to his comment as part of the fix so I added it to the answer for others:
Create a custom ModelBinder:
public class ReportModelBinder : IModelBinder
{
public object BindModel(
ControllerContext controllerContext,
ModelBindingContext bindingContext)
{
var xs = new XmlSerializer(typeof(Report));
return (Report)xs.Deserialize(
controllerContext.HttpContext.Request.InputStream);
}
}
Modify the Global.asax.cs to register this model binder against the Report type:
ModelBinders.Binders[typeof(Report)] = new Models.ReportModelBinder();