i am very new to mvc
//localhost:51525/api/products/GetPromotionTypes
the controller i have got is as bellow
public IEnumerable<Product> GetAll()
{
return Utility.GetDiscountItems();
}
public Product GetProduct(string Id)
{
return Utility.GetProduct(Id);
}
public String PostBag(Bag bagofItem)
{
return Utility.PostBagDiscountedItem(bagofItem);
}
public List<PromotionType> GetPromotionTypes()
{
return Utility.GetPromotionTypes();
}
when i call from the above uri it pointing to the controller GetProduc() but what i wanted it to call GetPromotionTypes()
what i have done wrong
appreciate all your help
If this is a WebAPI Controller, then you can only have one GET method per controller.
WebAPI was designed to only have 5 calls, GET (one item / list items), POST, PUT and DELETE per entity type. This allows for REST URLs, such as Folders/Get/5, Folders/Get etc.
You should add another API Controller for PromotionType.
Have a run through this tutorial here. http://www.asp.net/web-api/overview/getting-started-with-aspnet-web-api/tutorial-your-first-web-api
You do not have Routing set up properly. I suppose it treats your call as an simple GET request with GetPromotionTypes parameter.
Related
Does anyone know how to create a route in .NET MVC which contains attributes only? My code is as follows:
[Route("{listingCategoryDescription}/")]
public ActionResult CategorySearch(string listingCategoryDescription)
{
As you can probably tell I want the URL to simply contain a category. Is this possible? Or do I need to hard code at least one part of the route?
Many thanks.
Are you wanting the category passed in at the root URL? Like http://localhost/apples?
If so, this will work, but you will likely collide with other routes.
public class CategoriesController : Controller
{
[Route("{listingCategoryDescription}")]
public ActionResult Index(string listingCategoryDescription)
{
return Content("You picked category: " + listingCategoryDescription);
}
}
I have achieved creating the WebApi itself and I can browse it from the browser and get the output.
The thing which is not working for me is that I am trying to consume the WebAPI from an MVC Controller, and I have written the code for calling the WebAPI in my "cshtml" view.
But it doesn't work, as I am getting the error in loading the page, I understand I am doing something wrong. So the first question would be: am I doing this correctly, or is it completely wrong to create a WebAPI part in an MVC Project and then try to consume it in the same MVC project from the controller?
To answer your question, it's actually "as designed" and recommended to have your WebAPI and MVC client inside the same project. This is why you have both a RouteConfig.cs and a WebApiConfig.cs inside your MVC project. RouteConfig.cs is for your MVC controllers, and WebApiConfig.cs is obviously for your Api Controllers.
To have both in the same project is easy. What I do is add a folder named "API" in my root, and place all my WebAPI controllers in there. Keep in mind, and I'm sure you know, that the only difference between a WebAPI controller and an MVC controller is that a WebAPI controller inherits ApiController which is part of System.Web.Http (I believe) whereas an MVC controller inherits Controller which is part of System.Web.MVC.
Below is the proper way to make GET/PUT/DELETE/POST requests TO your WebAPI FROM an MVC front end. It doesn't matter if it's in the same project or not because you specify the WebAPI URL in your controller's constructor. If your WebAPI is on a different server than your front end MVC app, you will need to enable CORS support, which is a feature available in WebAPI version 2 and above.
This is the proper way to call a WebAPI from your front end, MVC client.
In your controller page, remove anything that has to do with DbContext, Entity Framework, etc. The reason is by default, the controller will want to perform CRUD operations by calling the DbContext, and we don't want this. We want to call the WebAPI instead to do this. When I refer to "Controller", I'm referring to the MVC controller, not the WebAPI controller.
First and foremost, declare some member variables in your MVC controller. The rest of your MVC controller will utilize these:
HttpClient client = new HttpClient();
HttpResponseMessage response = new HttpResponseMessage();
Uri contactUri = null;
In your MVC controller, create a constructor for your controller, as such:
public ContactController()
{
// set base address of WebAPI depending on your current environment
// the URL below, if the API is in the same project, will be something
// like "http://server/YourProjectName" - replace server with either
// "localhost", etc.
client.BaseAddress = new Uri("http://server/YourAPI/");
// Add an Accept header for JSON format.
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
}
Replace the Index action's code with something like the following. Note that the only relevant pieces are the client.GetAsync() call and the var contacts assignment. Everything else is not necessary for the context of this problem. The value inside the client.GetAsync() should be the name of your controller, prepended by any custom routing you set up in your WebApiConfig.cs - in my case, I added the api part in my route to distinguish between API calls and normal calls:
public ActionResult Index()
{
response = client.GetAsync("api/contact").Result;
if (response.IsSuccessStatusCode)
{
var contacts = response.Content.ReadAsAsync<IEnumerable<Contact>>().Result;
return View(contacts);
}
else
{
// add something here to tell the user hey, something went wrong
return RedirectToAction("Index");
}
}
Replace the Create action (the HttpPost action) with something like the following. Again, the only important piece is the client.PostAsJsonAsync() part - this is what calls the WebAPI's POST action which takes care of, in my case, inserting a new record into the database:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(Contact contact)
{
// Create a new product
response = client.PostAsJsonAsync("api/contact", contact).Result;
if (response.IsSuccessStatusCode)
{
return RedirectToAction("Index");
}
else
{
// add something here to tell the user hey, something went wrong
return RedirectToAction("Index");
}
}
Replace the Edit action (the non-HttpPost action) with something like the following. This was a little tricky because in order to edit, you had to retrieve the record first, so basically, the HttpPost version of Edit will contain somewhat similar code, with an additional line of code that performs the edit POST (PUT). Below, we're getting the response from the WebAPI by passing it a specific record ID. So, just like for Index (GET), we are doing the same thing only passing in the ID so we only get back one record. Then, we cast the response to an actual object that can be operated on in the View:
public ActionResult Edit(int id = 0)
{
response = client.GetAsync(string.Format("api/contact/{0}", id)).Result;
Contact contact = response.Content.ReadAsAsync<Contact>().Result;
if (contact == null)
{
return HttpNotFound();
}
return View(contact);
}
Replace the Edit action (the HttpPost action) with something like the following. Below, we're getting the record to be edited by calling client.GetAsync() and passing in the primary key as a parameter (contact_id). Then, we're getting the RequestUri from that response and saving it. Then, we're calling client.PutAsJsonAsync() and passing in the Uri.PathAndQuery (what we just saved) as well as the object to be edited.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(Contact contact)
{
response = client.GetAsync(string.Format("api/contact/{0}", contact.contact_id)).Result;
contactUri = response.RequestMessage.RequestUri;
response = client.PutAsJsonAsync(contactUri.PathAndQuery, contact).Result;
if (response.IsSuccessStatusCode)
{
return RedirectToAction("Index");
}
else
{
// add something here to tell the user hey, something went wrong
return RedirectToAction("Index");
}
}
Replace the Delete action (the non-HttpPost action) with something like the following. So again, we're getting the record from the database by simply calling client.GetAsync() and casting it to an actual object my app knows of.
public ActionResult Delete(int id = 0)
{
response = client.GetAsync(string.Format("api/contact/{0}", id)).Result;
Contact contact = response.Content.ReadAsAsync<Contact>().Result;
if (contact == null)
{
return HttpNotFound();
}
return View(contact);
}
Finally, replace the Delete action (the HttpPost action) with something like the following. Again, we're doing something similar to that of the Edit action. We are getting the record to be deleted, casting it to an object, and then passing that object into a client.DeleteAsync() call, as shown below.
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public ActionResult DeleteConfirmed(int id)
{
response = client.GetAsync(string.Format("api/contact/{0}", id)).Result;
contactUri = response.RequestMessage.RequestUri;
response = client.DeleteAsync(contactUri).Result;
return RedirectToAction("Index");
}
I've created a routing structure whereas the action part of the URL serves as a dynamic handler for picking a specific user created system name. i.e.
http://mysite.com/Systems/[SystemName]/Configure, where [SystemName] designates the name of the system they would like to configure.
The method that routes the system is the following:
public ActionResult Index(string systemName, string systemAction)
{
ViewData["system"] = _repository.GetSystem(systemName);
if (systemAction != "")
{
return View(systemAction);
}
else
{
// No Id specified. Go to system selection.
return View("System");
}
}
The above method sets the system to configure and routes to a static method where the view is displayed and a form awaits values.
The question I have is that when I create my configuration view, I lose my posted values when the form is submitted because it routes back to the above Index controller. How can I determine if data is being posted when hitting my above Index controller so that I can make a decision?
Thanks!
George
Annotate the controller method that handles the POST like this:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Index(string systemName, string systemAction)
{
// Handle posted values.
}
You can have a different method in your controller that handles the GETs:
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult Index(string systemName, string systemAction)
{
// No posted values here.
}
Note that, although I have copied the same method and parameters in each case, the signature for the second method (parameters and types) will have to be different, so that the two methods are not ambiguous.
The NerdDinner tutorial has examples of this.
I have two ASP.NET MVC Actions:
public ActionResult GetAll()
{
return GetOne(1);
}
public ActionResult GetOne(Int32 id)
{
return View(id);
}
As you can see, GetAll is calling the action GetOne. However, when GetAll() is called (calling GetOne(id) and should be returning GetOne view) MVC throws an error saying that there is no GetAll view. Huh?
How can I have GetAll call GetOne and use GetOne's view (which I thought was the logical thing to happen to begin with)?
public ActionResult GetOne(Int32 id)
{
return View(id, "GetOne");
}
Specifying the view name explicitly overrides the default, which is to use the action key in the route values collection, which is equal to "GetAll" in this case.
ASP.NET MVC, like many MVC frameworks, makes a lot of assumptions based on convention. If you don't follow their convention, you'll have a little more work to do. In this case, the convention is that their is a view with the same name as your action, in the folder that corresponds to the name of your controller.
If you controller is UsersController, and your action is GetAll, it expects to find a view Views/Users/GetAll.
If you want to return a view that corresponds with a different action, you need to specify that (instead of using the default):
return View(id, "GetOne")
i have different different pages which i want to call from one controller action
here is what i've done
public class TemplatesController : Controller
{
public ActionResult Select(int id)
{
return View("Temp"+(id));
}
}
i have different view pages like
Temp1, Temp2, Temp3,..etc...
the id is fetched properly
but i think there is a problem in concatenation
i want final result to be
return view("Temp1");
in another case it would be
return view("Temp2");
so that these pages can be called without creating controllers for each of the pages.
pls help.!
return View("Temp"+id.ToString());
The parameter is a String, so you can build the string up however you want.
string RetView = "Temp"+id.ToString();
return View(RetView);
so that these pages can be called
without creating controllers for each
of the pages.
Although i'm not sure if this is good practice, I suppose it depends on how many views you have.