How do I define a controller action that doesn't require a querystring? - asp.net-mvc

The following action does not require a querystring, but it does require the Id to be passed in the URL.
public ViewResult Details(int id)
{
Domain domain = db.Domains.Find(id);
return View(domain);
}
How do I change this so the name can be passed in the URL instead of the Id?
When I change that to the following, it produces an error "Sequence contains no elements" regardless of how I attempt to execute it.
public ViewResult Details(String name)
{
Domain domain = db.Domains.Where(d => d.Name == name).First();
return View(domain);
}
Any help is greatly appreciated.

"Sequence contains no elements" error is because your LINQ query is not returning any results for this where clause but you are trying to Apply the First() function on the result set (which is not available for your where condition in this case).
Use the First() function when you are sure that there is Atleast one element available in the resultset you are applying this function on. If there are no elements as the result of your LINQ expression, Applying First will throw the above error.
For the URL to have the name parameter instead of the integer id, just change the parameter type to string. Keep the variable name as id itself. because that is what the MVC Routing will use to help you write those pretty URLS.
So now your URL can be like
../SomeController/Details/someName
Where someName is going to be the parameter value of your Details action method.
I would use the FirstOrDefault and do a checking to see whether an element is available for the LINQ expression.FirstOrDefault will returns the first element of a sequence, or a default value if the sequence contains no elements.
public ViewResult Details(String id)
{
Domain domain = db.Domains.Where(d => d.Name == id).FirstOrDefault();
if(domain!=null)
return View(domain);
else
return View("NotFound") //Lets return the Not found View
}

Related

Asp.net web API Get method

I want to use select query in this Get method, because when I search the customer with id 4, it just shows its first record not all records, here is my method, i'm using simple mvc services.
I think that it shows only the first record because of #FirstOrDefault option , can anyone recommend me what query I should use or any other options?
` public sales_order Get(int id)
{
using (project_smartEntities entities = new project_smartEntities())
{
entities.Configuration.ProxyCreationEnabled = false;
return entities.sales_orders.FirstOrDefault(e => e.customer_id == id);
}
}`
As the name implies, .FirstOrDefault() returns the first (or default) matching record. (For reference types, the default is null.) If you want to find many records which match the query, you'd use the SQL-aptly-named .Where() instead:
return entities.sales_orders.Where(e => e.customer_id == id);
Since this returns a collection of objects instead of a single object, this would also of course necessitate changing the method's return type:
public IEnumerable<sales_order> Get(int id)
(Or any other applicable collection type. IEnumerable<> is just often the simplest.)

asp.net mvc4 controller allow null complex object

If I have this:
public ActionResult BuscarClientes(SomeClass c)
{ ... code ...}
And I access the url to this action without any parameter (so I don't give any elements to my model), I still get a newly created object. But, I'm wanting to get a NULL object instead if no arguments are given.
This is because I'm using this method as a search action method, and the first time the get is done I don't want to perform any validation and just return the view. After that, the post will be a GET method (its a search I need to make it a get request) with all the values in the query string.
How can I force the model binder to give me a null object if no parameters are given in the query string? Because as it is now, i get a new instance of SomeClass with all its properties set to null. Instead of just a null object.
Try specifying default value to the parameter
public ActionResult BuscarClientes(SomeClass c = null)
{ ... code ...}

Error in Details link of MVC3 application

I'm creating a Forum in asp.net MVC3 it contains link of Details which on click will show me details of particular record, but I am getting the following error when I click on the Details link.
The parameters dictionary contains a null entry for parameter 'id' of
non-nullable type 'System.Int32' for method
'System.Web.Mvc.ActionResult Details(Int32)' in
'Prjct_name.Controllers.DefaultController'. An optional parameter must
be a reference type, a nullable type, or be declared as an optional
parameter. Parameter name: parameters
Since I'm very new to MVC dont know how to deal with this
Still you want to use this URL [www.mydomain.com/Default/Details] you can set id as nullbale in controller :
public ActionResult Details(int? id)
{
if (id ==null)
{
// Do stuff
}
else
{ // Do something else
}
}
Sounds like your ActionResult looks like this:
public ActionResult Details(int id)
{
//Do stuff
}
Which would require the url be something like www.mydomain.com/Default/Details/1 where 1 is the id of the item but the url you are hitting is www.mydomain.com/Default/Details without the /[id]. In MVC, if one of your ActionResult prameters is 'id', that parameter is expected to be in the url...not the querystring.

How to handle null {id} on route?

What if a user hits my site with http://www.mysite.com/Quote/Edit rather than http://www.mysite.com/Quote/Edit/1000 In other words, they do not specify a value for {id}. If they do not, I want to display a nice "Not Found" page, since they did not give an ID. I currentl handle this by accepting a nullable int as the parameter in the Controller Action and it works fine. However, I'm curious if there a more standard MVC framework way of handling this, rather than the code I presently use (see below). Is a smoother way to handle this, or is this pretty mush the right way to do it?
[HttpGet]
public ActionResult Edit(int? id)
{
if (id == null)
return View("QuoteNotFound");
int quoteId = (int)id;
var viewModel = new QuoteViewModel(this.UserId);
viewModel.LoadQuote(quoteId);
if (viewModel.QuoteNo > 0)
{
return View("Create", viewModel.Quote.Entity);
}
else
return View("QuoteNotFound");
}
Your other options would be
Having two Edit actions ; One with int id as its parameters and another without any parameters.
Only having Edit(int id) as your action and letting your controller's HandleUnknownAction method to do what it's supposed to do when your entity is not found (this is a bit more complicated).
But I like your approach the best, as it's simple and correctly handles the situation.
BTW, you don't need that local variable, you can just do this for better readability :
//...
if (!id.HasValue)
return View("QuoteNotFound");
var viewModel = new QuoteViewModel(this.UserId);
viewModel.LoadQuote(id.Value);
//...
No real issue with the way you have it but semantically it's not really an invalid quote number, its that they have navigated to an invalid route that they should not have gone to.
In this case, I would tend to redirect to /quote and if you really want to show a message to the user just show an error banner or similar (assuming you have that functionality in your master page etc).
public ActionResult Edit(int? id)
{
if (id == null)
{
// You will need some framework in you master page to check for this message.
TempData["error"] = "Error Message to display";
return RedirectToAction("Index");
}
...
}
Use route constraint
You can always define a route constraint in your routes.MapRoute() call that won't pass through any requests with undefined (or non-numeric) id:
new { id = "\d+" }
This is a regular expression that checks the value of id to be numeric.
You will probably have to create a new route that defines this, because for other controller actions you probably don't want routes to be undefined. In this case, your controller action wouldn't need a nullable parameter, because id will always be defined.
Don't be afraid of using multiple routes. With real life applications this is quite common.

asp.net mvc - Route for string or int (i.e. /type/23 or /type/hats)

I have the following case where I want to accept the following routs
'/type/view/23' or '/type/view/hats'
where 23 is the Id for hats.
The controller looks something like this:
public class TypeController
{
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult View(int id)
{
...
}
}
Now if they pass in 23 no problems. If they pass in hats, I have some work to do. Now I was wondering in this case would I translate hats to 23 by using an ActionFilter that looks to see if the value passed in as the id is an int (if so check that it exists in the database) or if it is a string looks up the database for what the id of the string that has been passed in is. In either case if a match is not found I would want redirect the user to a different action.
Firstly is the approach I have named correct, secondly is it posible to do a redirect from within an ActionFilter.
Cheers
Anthony
Change your signature to accept a string. Then check if the value of id is an int. If it is, then lookup by id, if not lookup by name. If you don't find a match, then do your redirect.
public class TypeController
{
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult View(string id)
{
Product product = null;
int productID = -1;
if (int.TryParse( id, out productID))
{
product = db.Products
.Where( p => p.ID == productID )
.SingleOrDefault();
}
else
{
product = db.Products
.Where( p => p.Name == id )
.SingleOrDefault();
}
if (product == null)
{
return RedirectToAction( "Error" );
}
...
}
}
The reason that I would do this is that in order to know what controller/actions to apply, the framework is going to look for one that matches the signature of the route data that's passed in. If you don't have a signature that matches -- in this case one that takes a string -- you'll get an exception before any of your filters are invoked. Unfortunately, I don't think you can have one that takes a string and another that takes an int -- in that case the framework won't be able to tell which one should match if a single parameter is passed, at least if it's a number, that is. By making it a string parameter and handling the translation yourself, you allow the framework to do its work and you get the behavior you want -- no filter needed.
Unsure you can do this. I would think that you'd need to pass in a string and then check to see whether it's a numeric but there may be a better way.
As for redirecting use
return RedirectToAction("MyProfile", "Profile");
You can pass route values as part of the RedirectToAction call so you can pass in id's or names etc if that is what's required.
There are other ones like redirecting to routes which may also be helpful for what you want.

Resources