I've two action method in the following controller-
public class VisitMasterController
{
public ActionResult StartBrVisit()
{
string id=(Request.QueryString["id"].ToString(); //value=null here
}
public ActionResult BrNotPresent()
{
return RedirectToAction("StartBrVisit","VisitMaster" , new { id = "id", name = "name" });
}
{
After Redirect, Request.QueryString["id"] returns null.
My default route config is-
context.MapRoute(
"BR_default",
"BR/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional },
new[] { "OpinionLeader.Areas.BR.Controllers" } //add this line
);
Any help?
You have defined a route with a parameter named id so when you use new { id = "id" }, the RedirectToAction() method finds a match and adds the value as a route value, not a query string value (in the case of name, there is no match, so its value is added as a query string value). You could access it using
string id = (string)Request.RequestContext.RouteData.Values["id"]
However, it would be far easier to add a parameter to your method
public ActionResult StartBrVisit(string id)
Related
I want to send a parameter to a view from an action that resolves and sends that value. The issue is that when the parameter "arrives" to the view, it arrives null giving me an error when I try to manage it.
The code I have in the action is (it creates the parameter and send it):
public ActionResult CreateAccount(Account model)
{
try
{
if (ModelState.IsValid)
{
_repository = new Repository();
model.PublicadorId = GetPublicadorId();
model.CreatedDate = DateTime.Now;
model.ModifiedDate = DateTime.Now;
model.IsActive = true;
Int32 id = _repository.Store(model);
return RedirectToAction("SubirImagenes/" + id, "Account");
}
}catch{}
}
So, the action that manage the parameter sent is (note that I pass the parameter as a nullable to avoid errors, and the name of the parameter is the same as the name I use to call the RedirectToAction before):
[HttpPost]
[AuthorizeUser]
[ValidateAntiForgeryToken]
public ActionResult UploadImage(CompraVenta.Models.UploadFileModel fileModel, Int32? id)
{
string directory = #"C:\Folder\";
if (ModelState.IsValid)
{
if (fileModel != null && fileModel.File != null && fileModel.File.ContentLength > 0)
{
var fileName = Path.GetFileName(fileModel.File.FileName);
fileModel.File.SaveAs(Path.Combine(directory, fileName));
}
return RedirectToAction("Index");
}
return View();
}
[AuthorizeUser]
public ActionResult SubirImagenes()
{
return View();
}
Any help would be appreciated. The routing roules of my application is:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
You are using it wrong way, you have to pass parameter using this overload of RedirectToAction() which takes object of RouteValueDictionary as parameter.
Do like this:
return RedirectToAction("UploadImage", "Account", new {id = id});
UPDATE:
you cannot pass parameters the way told above if action is HttpPost, the workaround is to directly call action without using RedirectToAction like:
return UploadImage(null,id);
Call the method directly instead of using RedirectToAction like:
return UploadImage(null,id);
instead of
return RedirectToAction("UploadImage/" + id, "Account");
Note:- address in the browser would be of old method
You can add an anonymous object to the RedirectToAction for the action parameters:
return RedirectToAction("Index", "Home", new {id = id});
Finally I've found the solution. In the "get" action "SubirImagenes" I get the parameter and then, with a strong typed model, using a hidden field, I pass the parameter in the "post" action receiving it inside the model I pass as a parameter in that post action.
Execution of the following lines
#Html.ActionLink("Open",actionName: "DownloadExcelFile",
controllerName: "Excel",
routeValues: new { model = new ExcelModel(5, "JobName", "item.UserName") },
htmlAttributes: null)
returns Server Error in '/' Application, could you help me to fix them?
Note that when I change the name of the parameter, model -> id, I get an Error 404 instead of Server Error in '/' Application.
The model is
public class ExcelModel
{
public int InputA { get; set; }
public string InputB { get; set; }
public string UserName { get; set; }
public ExcelModel(int inputA, string inputB, string userName)
{
InputA = inputA;
InputB = inputB;
UserName = userName;
}
public ExcelModel()
{
InputA = 1;
InputB = "B1";
UserName = "NiceUser";
}
...
}
Controller is
public class ExcelController : Controller
{
public ActionResult Index()
{
var model = new ExcelModel(1, "B1", User.Identity.Name);
return View(model);
}
[HttpPost]
public ActionResult DownloadExcelFile(ExcelModel id)
{
// assume we create an an excel stream...
MemoryStream excelStream = id.BuildSpreadsheet();
return new FileStreamResult(excelStream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
{
FileDownloadName = "myfile.xslx"
};
}
}
RouteConfig is the standard one
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
Finally, as mentioned earlier, the method itself is fine, since it works perfectly with submit, as below:
#using (Html.BeginForm("DownloadExcelFile", "Excel"))
{
<fieldset>
// fields names and values
<p>
<input type="submit" value="Open Excel"/>
</p>
</fieldset>
}
1) You can't pass an entire class as a route value param. The helper has to be able to put whatever you pass into a URL, which means it has to be something that can be converted to a string value. It might be possible to JSON encode the model and then pass the JSON string for the param, but the helper isn't going to make such assumptions for you, nor would it necessarily know how to JSON encode it for you, if it did.
2) When you just pass the id, you get a 404 because your action doesn't not accept an int for id, but rather expects ExcelModel, which as we discussed in #1, is not possible to pass via URL.
Your controller method is marked with the HttpPost attribute. This means that it only accepts POST-requests and not GET-requests. Normal link visits are GET-requests, so that is probably the problem. (Read more here)
Remove the HttpPost attribute and see if that fixes the problem.
I want to have links http://localhost:2409/Account/Confirmation/16 and that link http://localhost:2409/Account/Confirmation/ (without parametr). But with this action methods, it isn't working. Why?
public ActionResult Confirmation(int id, string hash)
{
Some code..
return View();
}
second, I just want to return View, if parametr is empty.
public ActionResult Confirmation()
{
return View();
}
Error (translated):
The current request for action on a controller Confirmation
AccountController is ambiguous between the following methods of
action: System.Web.Mvc.ActionResult Confirmation (Int32,
System.String) for type TC.Controllers.AccountController
System.Web.Mvc.ActionResult Confirmation () for type
TC.Controllers.AccountController
You cannot have multiple actions with the same name using the same HTTP verb (in your case GET.) You can name your actions differently but this means the link will change or you can use different VERB but this can also leads to other problems like you cannot just enter the link in your browser.
What you should do is to change your id to be optional with int? and merge your two actions into one:
public ActionResult Confirmation(int? id, string hash)
{
if(id.HasValue)
{
//Some code.. using id.Value
return View();
}
//There was no Id given
return View();
}
You may also need to allow in your route that the id is optional. If you are using the default routes this should be the default setting:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
There is no need to make 2-methods for it. Your HTTP request get confused that which ActionMethod should be called on both cases;
http://localhost:2409/Account/Confirmation/16
http://localhost:2409/Account/Confirmation/
Instead of all this, just create a single method. Make its parameter optional or assign some default value to the parameters. Here are 2-examples to understand it.
// 1. Default value to paramter
public ActionResult Confirmation(int id = 0, string hash = null)
{
//Some code..
return View();
}
// 2. Make id optional
public ActionResult Confirmation(int? id, string hash)
{
//Some code..
return View();
}
You can adopt any one approach from them.
I'm trying to setup a custom route in MVC to take a URL from another system in the following format:
../ABC/ABC01?Key=123&Group=456
The 01 after the second ABC is a step number this will change and the Key and Group parameters will change. I need to route this to one action in a controller with the step number key and group as paramters. I've attempted the following code however it throws an exception:
Code:
routes.MapRoute(
"OpenCase",
"ABC/ABC{stepNo}?Key={key}&Group={group}",
new {controller = "ABC1", action = "OpenCase"}
);
Exception:
`The route URL cannot start with a '/' or '~' character and it cannot contain a '?' character.`
You cannot include the query string in the route. Try with a route like this:
routes.MapRoute("OpenCase", "ABC/ABC{stepNo}",
new { controller = "ABC1", action = "OpenCase" });
Then, on your controller add a method like this:
public class ABC1 : Controller
{
public ActionResult OpenCase(string stepno, string key, string group)
{
// do stuff here
return View();
}
}
ASP.NET MVC will automatically map the query string parameters to the parameters in the method in the controller.
When defining routes, you cannot use a / at the beginning of the route:
routes.MapRoute("OpenCase",
"/ABC/{controller}/{key}/{group}", // Bad. Uses a / at the beginning
new { controller = "", action = "OpenCase" },
new { key = #"\d+", group = #"\d+" }
);
routes.MapRoute("OpenCase",
"ABC/{controller}/{key}/{group}", // Good. No / at the beginning
new { controller = "", action = "OpenCase" },
new { key = #"\d+", group = #"\d+" }
);
Try this:
routes.MapRoute("OpenCase",
"ABC/{controller}/{key}/{group}",
new { controller = "", action = "OpenCase" },
new { key = #"\d+", group = #"\d+" }
);
Then your action should look as follows:
public ActionResult OpenCase(int key, int group)
{
//do stuff here
}
It looks like you're putting together the stepNo and the "ABC" to get a controller that is ABC1. That's why I replaced that section of the URL with {controller}.
Since you also have a route that defines the 'key', and 'group', the above route will also catch your initial URL and send it to the action.
There is no reason to use routing based in querystring in new ASP.NET MVC project. It can be useful for old project that has been converted from classic ASP.NET project and you want to preserve URLs.
One solution can be attribute routing.
Another solution can be in writting custom routing by deriving from RouteBase:
public class MyOldClassicAspRouting : RouteBase
{
public override RouteData GetRouteData(HttpContextBase httpContext)
{
if (httpContext.Request.Headers == null) //for unittest
return null;
var queryString = httpContext.Request.QueryString;
//add your logic here based on querystring
RouteData routeData = new RouteData(this, new MvcRouteHandler());
routeData.Values.Add("controller", "...");
routeData.Values.Add("action", "...");
}
public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
{
//Implement your formating Url formating here
return null;
}
}
And register your custom routing class
public static void RegisterRoutes(RouteCollection routes)
{
...
routes.Add(new MyOldClassicAspRouting ());
}
The query string arguments generally are specific of that controller and of that specific application logic.
So it will better if this isn't written in route rules, that are general.
You can embed detection of query string on action argument in the following way.
I think that is better to have one Controller for handling StepNo.
public class ABC : Controller
{
public ActionResult OpenCase(OpenCaseArguments arg)
{
// do stuff here
// use arg.StepNo, arg.Key and arg.Group as You need
return View();
}
}
public class OpenCaseArguments
{
private string _id;
public string id
{
get
{
return _id;
}
set
{
_id = value; // keep original value;
ParseQueryString(value);
}
}
public string StepNo { get; set; }
public string Key { get; set; }
public string Group { get; set; }
private void ParseQueryString(string qs)
{
var n = qs.IndexOf('?');
if (n < 0) return;
StepNo = qs.Substring(0, n); // extract the first part eg. {stepNo}
NameValueCollection parms = HttpUtility.ParseQueryString(qs.Substring(n + 1));
if (parms.Get("Key") != null) Key = parms.Get("Key");
if (parms.Get("Group") != null) Group = parms.Get("Group");
}
}
ModelBinder assign {id} value to the id field of OpenCaseArguments. The set method handle querystring split logic.
And keep routing this way. Note routing get your querystring in id argument.
routes.MapRoute(
"OpenCase",
"ABC/OpenCase/{id}",
new {controller = "ABC", action = "OpenCase"}
);
I have used this method for getting multiple fields key value on controller action.
I've got a very basic ASP.Net MVC project where I'd like to use a parameter name of id on one of my controller actions. From everything I've read that shouldn't be a problem but for some reason using a parameter name of id fails to get the value extracted from the query string but if I change it to any other different name it will work.
I only have a single route in my global.asx
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = "" } // Parameter defaults
);
My controller method is:
public ActionResult Confirm(string id)
{
....
}
A URL of http://mysite/customer/confirm/abcd works. A URL of http://mysite/customer/confirm?id=abcd fails.
If I change the controller method to:
public ActionResult Confirm(string customerID)
{
....
}
then a URL of http://mysite/customer/confirm?customerID=abcd works.
Is there something special about using "id" as a parameter in an ASP.Net MVC query string?
Update: Changed id from 1234 to abcd, my id's are actually strings.
If you do not apply an id parameter (either querystring or POST), the system just ignores it, and you can remove the "id" parameter in your controller:
public ActionResult Confirm()
In your case, you would just stick with the id parameter. Why make an ugly customerID parameter, when id is "mapped" automatically?
This is an easy and simple example of the use of id parameter.
public ActionResult Confirm(int? id)
{
if (id.HasValue && id.Value > 0) // check the id is actually a valid int
_customerServer.GetById(id.Value);
// do something with the customer
return View();
}
This works too, for me. We're doing it in our application right now with a standard route:
public ActionResult Confirm(string id)
{
if (!string.IsNullOrEmpty(id)) // check the id is actually a valid string
_customerServer.GetByStringId(id);
// do something with the customer
return View();
}
If you need to have id in query string, then don't create route with 'id' parameter.
In case you have route "{controller}/{action}" then you can use public ActionResult Confirm(string id) as your controller method.
Routes don't care about query strings.