In my project I have to redirect from one controller to another controller which is present inside the Areas named SIP. If use the following method the redirection works successfully and also the TempData value is passed to the other controller:
TempData["sipModel"] = 1;
return RedirectToAction("Index", "Home", new { area = "SIP" });
But in this case the URL gets changed while my requirement is to keep the same URL, to achieve that I went though other answers and used the method TransferToAction()
mentioned
in this answer This works perfectly and I'm able to redirect to the other area without changing the URL with the following code:
TempData["sipModel"] = 1;
return this.TransferToAction("Index", "Home", new { area = "SIP"});
However, in this case the TempData value is not retained and I get Null Reference Exception while trying to read the same.
I tried to use the following code mentioned in the other answer:
public static TransferToRouteResult TransferToAction(this System.Web.Mvc.Controller controller, string actionName, string controllerName, object routeValues)
{
controller.TempData.Keep();
controller.TempData.Save(controller.ControllerContext, controller.TempDataProvider);
return new TransferToRouteResult(controller.Request.RequestContext, actionName, controllerName, routeValues);
}
But this doesn't work out. Can somebody please suggest me how can I fix this or any other better approach to achieve this result. Thanks.
Edited:
The URL is like:
I have a complex data in a class which also needs to be passed from the one controller to the other (which is present in the Area SIP), for that I've been using TempData, I've used an integer here just as a sample.
In the first controller method I've if-else condition, so:
if (companyCode = 'X')
return View();
else
TempData["sipModel"] = 1;
return RedirectToAction("Index", "Home", new { area = "SIP" }); OR (this.TransferToAction("Index", "Home", new { area = "SIP"});)
Server.TransferRequest
is completely unnecessary in MVC. This is an antiquated feature that was only necessary in ASP.NET because the request came directly to a page and there needed to be a way to transfer a request to another page. Modern versions of ASP.NET (including MVC) have a routing infrastructure that can be customized to route directly to the resource that is desired. There is no point of letting the request reach a controller only to transfer it to another controller when you can simply make the request go directly to the controller and action you want.
So, given your example is not a complete set of requirements I will make the following assumptions. Adjust these as necessary for your requirements.
cid
or pid
on the home page, we will send the request to the Index
action of the HomeController
of the SID
area."sipModel"
with value 1
in the latter case and omit the parameter in the first case.First of all, we subclass RouteBase
and put our custom logic there. A more complete scenario might have dependent services and options passed in through the constructor, and even have its own MapRoute
extension methods to wire it together.
public class CustomHomePageRoute : RouteBase
{
public override RouteData GetRouteData(HttpContextBase httpContext)
{
RouteData result = null;
// Only handle the home page route
if (httpContext.Request.Path == "/")
{
var cid = httpContext.Request.QueryString["cid"];
var pid = httpContext.Request.QueryString["pid"];
result = new RouteData(this, new MvcRouteHandler());
if (string.IsNullOrEmpty(cid) && string.IsNullOrEmpty(pid))
{
// Go to the HomeController.Index action of the non-area
result.Values["controller"] = "Home";
result.Values["action"] = "Index";
// NOTE: Since the controller names are ambiguous between the non-area
// and area route, this extra namespace info is required to disambiguate them.
// This is not necessary if the controller names differ.
result.DataTokens["Namespaces"] = new string[] { "WebApplication23.Controllers" };
}
else
{
// Go to the HomeController.Index action of the SID area
result.Values["controller"] = "Home";
result.Values["action"] = "Index";
// This tells MVC to change areas to SID
result.DataTokens["area"] = "SID";
// Set additional data for sipModel.
// This can be read from the HomeController.Index action by
// adding a parameter "int sipModel".
result.Values["sipModel"] = 1;
// NOTE: Since the controller names are ambiguous between the non-area
// and area route, this extra namespace info is required to disambiguate them.
// This is not necessary if the controller names differ.
result.DataTokens["Namespaces"] = new string[] { "WebApplication23.Areas.SID.Controllers" };
}
}
// If this isn't the home page route, this should return null
// which instructs routing to try the next route in the route table.
return result;
}
public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
{
var controller = Convert.ToString(values["controller"]);
var action = Convert.ToString(values["action"]);
if (controller.Equals("Home", StringComparison.OrdinalIgnoreCase) &&
action.Equals("Index", StringComparison.OrdinalIgnoreCase))
{
// Route to the Home page URL
return new VirtualPathData(this, "");
}
return null;
}
}
To wire this into MVC, we just edit the RouteConfig
as follows:
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
// Add the custom route to the static routing collection
routes.Add(new CustomHomePageRoute());
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
namespaces: new string[] { "WebApplication23.Controllers" }
);
}
}
This passes an extra route value sipModel
to the PID
area's HomeController.Index
method. So, we need to adjust the method signature to accept that parameter.
namespace WebApplication23.Areas.SID.Controllers
{
public class HomeController : Controller
{
// GET: SID/Home
public ActionResult Index(int sipModel)
{
return View();
}
}
}
As you can see, there really is no reason to use TempData
, either. TempData
relies on session state by default. It has its uses, but you should always think twice about using session state in MVC as it can often be avoided entirely.