Passing integer values from view to controller (mvc) through href - asp.net-mvc

I 'm doing a dot net project (MVC) in which I want to pass integers (hard coded university ids) from view to Controller.
In view I 'm doing
PU
UET
GC
where admin is the CONTROLLER & applied is ACTION METHOD
in ACTION METHOD (applied in Admin)
public ActionResult applied(string uniId)
{
Processing of admissions on the basis of uniId
}
but when I 'm compiling this , uniId contains NULL instead of actual integer passed by PU etc.
Kindly help me out

ASP.NET MVC will only provide the value if the parameter is named id. You have to options. First is renaming the parameter:
public ActionResult applied(string id)
{
Processing of admissions on the basis of uniId
}
Second is creating a new route in RouteConfig above the default route:
routes.MapRoute(
"Applied", // Route name
"Admin/applied/{uniId}", // URL with parameters
new { controller = "Admin", action = "applied" } // Parameter defaults
);

Related

Attribute Routing : Object reference not set to an instance of an object

I'm using this codes to Attribute Routing .
my controller :
[RouteArea("Administrator")]
[Route("{action}")]
public partial class HomeController : Controller
{
[HttpGet]
[Route("~/Home/Template/{id}")]
public virtual ActionResult Template(string template)
{
switch (template.ToLower())// error :Object reference not set to an instance of an object..
{
case "main":
return PartialView(Url.Content(MVC.Administrator.Home.Views.Main));
default:
throw new Exception("template not known");
}
}
}
RouteConfig :
internal static class RouteConfig
{
internal static void RegisterRoutes(AreaRegistrationContext context)
{
context.MapRoute(
"Administrator_default",
"Administrator/{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional },
namespaces: new[] { string.Format("{0}.Controllers", typeof(RouteConfig).Namespace) });
}
}
url : http://localhost:22738/home/template/main
how to use Attribute Routing ?
Is there a way to solve the problem? I have no idea
It would behoove you spend some time reading the documenation for attribute routing. See: http://blogs.msdn.com/b/webdev/archive/2013/10/17/attribute-routing-in-asp-net-mvc-5.aspx
First, you haven't enabled attribute routing. You need the following in RouteConfig.cs:
routes.MapMvcAttributeRoutes();
Second, you can't apply [Route] to a controller class. You can use [RoutePrefix] if that's what you're looking for. However, bear in mind, that if you include a param in your route prefix, all your action must accept that param. Although, since you have a param of action here, it's entirely possible that you just don't understand how this works. You don't pass the action name with attribute routing. The action that is hit is determined by the one that has the matching route.
Third, when you define a route on an action, you need only specify the portion of the route not covered by RouteArea or RoutePrefix. Using the tilde (~) says that you want to ignore all set prefixes and define the whole route for the action, if that's what you actually want here, that's fine, but just keep in mind that you don't have to follow the /Controller/Action/{id} convention employed by the default route in RouteConfig.cs. The whole point of attribute routing is to define custom routes easily. If you're going to rely on the default route, you might as well just use that and forget about attribute routing.
Finally, in your route, you're accepting the param, id, but your action doesn't take it. Instead it has its own param of template. The params need to match or either the route will not match or the action won't be able to work.
To summarize, the following is likely what you're looking for:
[RouteArea("Administrator")]
[RoutePrefix("home")]
public partial class HomeController : Controller
{
[Route("template/{template}")]
public virtual ActionResult Template(string template)
{
switch (template.ToLower())// error :Object reference not set to an instance of an object..
{
case "main":
return PartialView(Url.Content(MVC.Administrator.Home.Views.Main));
default:
throw new Exception("template not known");
}
}
}

Pass a big object to an action on a controller from a view

I want to pass a big object to a controller's action from a view. Like so:
View
<div>#Html.ActionLink("Send us an email", "Index",
"Email", new { o = #Model.Exception }, null)</div>
Controller
public class EmailController : Controller
{
[AllowAnonymous]
public ActionResult Index(object o)
{
new BaseServices.Emailer().SendEmail(o);
return View();
}
}
The thing is: the object being passed is so large that I guess that MVC is unable to make an argument out of that and add it to the route table/dictionary. So, my email controller's Index action is never called. The code bombs off somewhere in between.
No, you can't do this. ASP.NET MVC is not some magic. It relies on standard HTTP and HTML. And as you know in HTTP when you are using a GET request, there's no notion of .NET objects. You cannot ask how to pass an object in a web application because this is not defined.
There's a notion of query string parameters. So that's what you can pass => simple query string parameters:
#Html.ActionLink(
"Send us an email",
"Index",
"Email",
new { id = Model.Exception.Id, text = Model.Exception.Text },
null
)
Where the magic comes is that ASP.NET MVC will now use the 2 simple query string parameters (id and text) to map them to the corresponding properties of your view model inside the controller action.
But of course for this to work ASP.NET MVC needs to know the type of the model. You cannot just use object because this type doesn't have id nor text properties.
So:
public ActionResult Index(MyViewModel o)
Now but what about sending complex types? Well, the question that you have to ask to yourself is why on the first place this type was passed to the view? Was it because tfhe user was supposed to edit some of its properties? Is so then you should use an HTML form containing input fields allowing the user to edit them.
But since you have stuck this object into an anchor then what's the point? The server could fetch this object from wherever it fetched it in the first place. So all you need is to pass a simple id to the server:
#Html.ActionLink(
"Send us an email",
"Index",
"Email",
new { id = Model.Exception.Id },
null
)
and have the controller action take this id as parameter:
public ActionResult Index(int id)
Alright now you know the id => therefore you could retrieve the corresponding entity from wherever this entity is persisted.
Now some people might suggest you storing the object into the session before rendering the view and then retrieving this object from the session. Personally I am not a big fan of the session as it introduces state into the application. This means that you can never invoke the second action without first invoking the first action. This also means that you cannot bookmark the second action into the browser favorites. This also means that if you are running your application in a web-farm you can no longer store the session in-memory => you will have to use an out-of-process storage for this session. Sessions are way too much of a hassle.
You can't really pass it in the view.
Instead, consider storing the exception in TempData in the controller that renders the view....
public ActionResult DisplayErrorAndOptionToEmailIt()
{
TempData["LastError"] = m.Exception;
return View();
}
and then when the request comes in retrieve it from temp data and email it
public ActionResult SendTheEmail()
{
var e = TempData["LastError"] as Exception;
if (e != null)
{
EmailHelper.SendExceptionEmail(e);
}
return View();
}
On a side note, it's not the best practice to store complete objects. If possible, store only what you need:
public ActionResult DisplayErrorAndOptionToEmailIt()
{
TempData["LastError"] = m.Exception.Message;
return View();
}

Why do you need a route defined for Html.Action?

I have created an otherwise empty ASP.NET MVC 3 application with 2 controllers, HomeController and OtherController.
HomeController.cs looks like this:
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
}
Index.cshtml looks like this:
#Html.Action("Index", "Other")
And, of course, Othercontroller.cs:
public class OtherController : Controller
{
[ChildActionOnly]
public ActionResult Index()
{
return Content("OK!");
}
}
So far, so good. I run the app, and it tells me everything is OK!
Now, I take the default RegisterRoutes from Global.asax.cs:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
}
And I crumple it up, so that no routes match OtherController:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute("Default", "", new { controller = "Home", action = "Index" });
}
Now, when I run the page, it crashes with this error message:
System.InvalidOperationException: No route in the route table matches the supplied values.
Source Error:
Line 1: #Html.Action("Index", "Other")
I specified the controller name and action name in the call to .Action. No URLs are being generated, and no requests are being made. Why does routing even need to get involved?
I think that this blog post will help you understand a little more:
http://blogs.charteris.com/blogs/gopalk/archive/2009/01/20/how-does-asp-net-mvc-work.aspx.
Essentially, routing is involved in determining which controller to 'fire up' to handle the request and appropriate action to invoke based on the parameters that you sent and the MVCRouteHandler uses those to make a decision. Just because you tell it which controller in your action does not make it magically ignore the routing table, go straight to that controller class and bypass all the other MVC goodness that happens in the back-end. Remember, these #HTML.Action methods can take a whole lot of overloads which could influence which route in the routing table to use (think URL structure for instance).
The MVC paths are not to static content and as such, have to be parsed through the URLRoutingModule which uses the routing table to decide on what to do. Since you have no matching route - you get an error.
EDIT
In my diatribe, I did not actually address your final statement. You're right, no URL was generated, but a request to the application was generated. HTML.Action still will use routing to determine what controller, action, area, parameters to use. I think it be fair to say in simple terms that it's like generating an ActionLink and clicking it for you.
Routing got involved by using Html.Action on a controller. When the engine couldn't find the "Other" HtmlHelper with an action of "Index" it defaulted to executing that path which means passing through routing. No route matched so it threw an error.
InvalidOperationException The required virtual path data cannot be found.
http://msdn.microsoft.com/en-us/library/ee721266.aspx
The solution for me was as follows:
I had the following line that was giving me an error:
#{Html.RenderAction("ActionName", "ControllerName");}
Adding a thrid parameter solved the error:
#{Html.RenderAction("ActionName", "ControllerName", new { area = string.Empty });}

Value cannot be null. Parameter name: String in asp.net mvc C#

I am pretty new to asp.net mvc. I want to get the parameter string in my url
http://localhost/Item/ItemSpec/3431?dep=62&cat=129&tab=2
How can I get the value=3431?
I tried to used HttpContext.Current.Request.QueryString["id"], but it's not work. 3431 is the id of the item that display in my page, that's why I used ["id"].
Thanks you so much.
The 3431 is part of the path of the request, not part of the query string. You could use HttpRequest.Path to get at the path, but MVC routing should allow you to simply write a controller method which accepts the ID as a parameter. I suggest you read up on how to configure routing. (Just searching for ASP.NET routing or MVC routing will give you lots of articles.)
Assuming the default route is configured in Global.asax ({controller}/{action}/{id}) you could have your controller action take an id parameter and the default model binder will automatically set its value:
public ActionResult Foo(string id)
{
...
}
If you want to fetch this id value from some other portion of your code that does have access to an HttpContext you need to fetch it from the RouteData:
var id = HttpContext.Request.RequestContext.RouteData["id"];
RouteData is available in all standard MVC locations. In your example you have used the static HttpContext.Current property which is something that you should never use. I suspect that you are trying to fetch this id from a portion of your code where you are not supposed to have access to the HttpContext. So you'd better fetch this id using standard techniques and then pass it as parameter to other parts of your code.
If Item is your controller, and ItemSpec is action, you can get the Id just by
public ActionResult ItemSpec(int id) { }
You routing have to be setup to:
context.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index" }
);
If you haven't changed your routing so it's still defined as it was when you created Asp.net MVC Web project then this should be one of your controllers:
public class ItemController : ControllerBase
{
...
public ActionResult ItemSpec(int id, int dep, int cat, int tab)
{
// implementation that uses all four values
}
...
}
This is of course just one of the actions in it. There may be others as well. Most likely the Index one that's generated by default and is also used by default routing...

Removing direct reference to URL in view when two different URLs map to single controller action?

Basically I'm looking for the best way to remove the need to hard code any actual URLs within views when two different URLs call the same controller action. As shown below, two routes define different URLs, one for creating a new customer, whilst the other is for editing an existing customer. Inside the controller action it determines what to do by checking the value of AccountNumber - if it was not provided (null) then it knows that it is creating a new customer.
routes.MapRoute(
"Customer_Edit",
"Customer/Edit/{CustNum}",
new { controller = "Customer", action = "Edit", AccountNumber = "{CustNum}" }
);
routes.MapRoute(
"Customer_Create",
"Customer/Create",
new { controller = "Customer", action = "Edit" }
);
The downside to this approach is that you can't use Url.Action(...) in the views to determine the URL because there are two different URLs mapping to the controller action. I had hoped that the call to Url.Action(...) would determine which to use by the "RouteValues" provided, but it just appears to use the 1st matching route defined. So in this case if you call
Url.Action("Edit", "Customer", new { CustNum = 2 })
you get "Customer/Edit/2" as you'd expect, but if you call
Url.Action("Edit", "Customer")
the view outputs the URL "Customer/Edit/{CustNum}".
Is there anyway using this configuration that you would not need to hard code URLs into the view? Or is it considered better practise to have a separate action for creating new customers and another action for editing customers, so you end up with the following
public class CustomerController : Controller
{
public ActionResult Create()
{ return CreateOrEdit(null); }
public ActionResult Edit(int custNum)
{ return CreateOrEdit(custNum); }
private ActionResult CreateOrEdit(int? custNum)
{....}
}
Use Url.RouteUrl instead and specify the route you want. In addition to actually working, RouteUrl is on the order of 10* faster than Action.

Resources