cshtml / view without an action method - asp.net-mvc

Can I serve a cshtml page as a view without writing an action method?
So, if I have a controller called Help and a view called Money.cshtml I want to access it as localhost/help/money without writing an action method?

You could do something like the following.
Define a route that maps to just one action e.g.:
routes.MapRoute(
"Help_default", // Route name
"help/{path}", // URL with parameters
new { controller = "About", action = "Page" }
);
Then your help controller could look like the following. It basically just grabs the path from the URL and passes that as the model to the view.
public class HelpController : Controller
{
public ViewResult Page(string path)
{
return View("Page", path);
}
}
Your Page view could then look like:
#model string
#{
string viewPath = string.Format("~/Views/Help/{0}.cshtml", Model);
ViewEngineResult result = ViewEngines.Engines.FindView(this.ViewContext.Controller.ControllerContext, viewPath, null);
if (result.View != null)
{
#Html.Partial(viewPath)
} else {
// Define a not found view in the shared folder?
#Html.Partial("NotFound")
}
}
Which basically checks to see if a view exists with that path or not. It feels a bit dirty but I think it would work.

Related

Redirect to Controller with query params outside of Controller context

I've looked around online quite a bit, but haven't been able to figure out a solution to my current predicament. As the title suggest I am attempting to redirect a user to one of my view controllers with the following code:
// this is in a service that's beyond the Controller scope
httpContext.Response.Redirect("/Login");
This works fine; however, I need to pass in a query param as well. Essentially I'm looking to do something like this:
// this is in a service that's beyond the Controller scope
httpContext.Response.Redirect("/Login?NoAccess=true");
Where my View Controller looks like this:
[AllowAnonymous]
[HttpGet("~/Login")]
public async Task<IActionResult> Index([FromQuery]bool noAccess = false)
{
// implementation
}
As one might imagine, this doesn't work and the value isn't passed to my controller.
Is it possible to pass query param(s) using a redirect outside of a Controller context?
Thanks,
Ruben
Try using the RedirectToAction or RedirectToRoute instead. Will return a IActionResult to do the redirect. With it you can specify an object with the parameters. Like this:
public IActionResult Action()
{
return this.RedirectToAction("Index", "ControllerName", new {
noAccess = true
});
}
You can try
public IActionResult Action()
{
return Redirect(Url.Action("Index", "ControllerName") + "?noAccess=true"));
}
Also, you can try adding entire url like :
public ActionResult YourAction()
{
// ...entire url
return Redirect("http://www.example.com");
}
Even you could return a JsonResult with the new url and perform the redirect with javascript.
public ActionResult YourAction()
{
// ...
return Json(new {url = "http://www.example.com"});
}
$.post("#Url.Action("YourAction")", function(data) {
window.location = data.url;
});

Umbraco MVC-like routing

I currently have a controller that needs to process parameters passed to umbraco's actions. What I did was adding a controller for my Document Type:
public class MyDocumentTypeController : RenderMvcController
{
public ActionResult SignUp(RenderModel model, [Bind(Prefix="rc")] string myArgument = null)
{
// some logic
return View(model);
}
}
Now I'm able to pass arguments to that action. Assuming my content of MyDocumentType is available under address http://mypage/mydocumenttype, so I can pass arguments to my action like this: http://mypage/mydocumenttype/signup?rc=1234ef. What I dislike is:
I cannot put constraints on the argument
I can't make use of MVC-like paths, like: http://mypage/mydocumenttype/signup/1234ef
To achieve it I added routing:
public static void RegisterRoutes(RouteCollection routes)
{
routes.MapUmbracoRoute(
"MyDocumentType",
"MyDocumentType/{action}/{myArgument}",
new { controller = "MyDocumentType", action = "Index", myArgument = UrlParameter.Optional },
/* WHAT GOES HERE? */,
new { myArgument = #"^[a-zA-Z0-9]{5}$" });
}
However, if I create plain-old-vanila MVC routing I loose Umbraco's context which I need. If I use MapUmbracoRoute I don't know what IRouteHandler should be passed. Any ideas?

ASP.NET MVC Clean way to inject partial view from action

I have an app with many widgets and their content depends on the user requesting specific route. Simply put: if widget action is requested, its content must be rendered, otherwise it's empty. Consider routes/actions like this:
~/MyApp/Index -> without model; app HTML, without any widgets
~/MyApp/Foo/{id} -> uses FooModel; if ModelState is valid, returns
Index HTML with injected partial view of Foo's widget to div#foo;
otherwise redirects to Index.
~/MyApp/Bar/{id} -> same as Foo, but different model and widget
My foo action :
public ActionResult Foo(string id) {
if (ModelState.IsValid) {
var response = FooService.GetData(id);
// Inject Foo widget to Index
}
return RedirectToAction("Index");
}
I know that it is possible to use ViewBag or other means to send variables and using the condition to decide whether to render partial view or not. But... there should be a better way to do this, right?
I use MVC's Html.RenderActionResult when I want to build shared views with non-trivial binding logic (calling the database, composing complex objects, etc). The binding logic for each widget is contained in a PartialViewResult method, which is called from the *.cshtml file using Html.RenderAction().
ContentController:
public ActionResult Index(int id)
{
var indexViewModel = new IndexViewModel
{
Id = id,
Title = "My Title",
SubHeader = "Wow its 2016"
};
return View(indexViewModel);
}
public PartialViewResult PopularContent(int id)
{
var popularContentViewModel = new List<PopularContentViewModel>();
// query by id to get popular content items
return PartialView("_PopularContent", popularContentViewModel);
}
public PartialViewResult Widget2(int id)
{
return PartialView("_Widget2Partial");
}
Index.cshtml:
#model StackOverflow.RenderAction.ViewModels.IndexViewModel
<h1>#Model.Title</h1>
<h2>#Model.SubHeader</h2>
--RenderAction will call out to the specified route.
--Note the use of the Id parameter from the viewmodel.
#{Html.RenderAction("PopularContent", "Content", new {Model.Id});}
ASP.NET MVC Attribute Routing could a be a nice solution for this:
In your controller:
public class WidgetController : Controller
{
[Route("myapp/foowidget", Name = "FooWidget")]
public ActionResult FooWidget()
{
//create any model and return any view or partial or redirect
}
[Route("myapp/boowidget/{id:int}", Name = "BooWidget")]
public ActionResult BooWidget(int id)
{
//create any model and return any view or partial or redirect
}
}
And then in a View, you can call the Route by name:
#Url.RouteUrl("FooWidget")
or
#Url.RouteUrl("BooWidget")
or
#Html.RenderPartial("FooWidget")
#Url.RouteUrl("BooWidget") will render or concatenate the id that is in current url, if url is /myapp/something/id, because of your Route attribute definition: "myapp/boowidget/{id:int}". In fact #Url.RouteUrl("BooWidget") might extract the id from any current url of the format /controllerName/action/id, though you will have to test for sure.
And notice how you can have a separation of concerns with your WidgetController and your url Routes are not dependent on that controller's name in any way. That is a nice feature of Attribute Routing, you can declare custom routes as well as organize your controllers and break from nameing convention dependency of a controllerName being part of the url controllerName/action a user sees in their browser.
In regards to Html.RenderPartial, I am not sure if RenderPartial "connects" or will be able to route to your RouteName like "FooWidget". If it does great.
If not your solution is this:
public class WidgetController : Controller
{
public ActionResult FooWidget()
{
//model, you choose, return a partial
}
public ActionResult RedirectUser()
{
//do a redirect
}
public ActionResult BooWidget()
{
//any model, any partial
}
public ActionResult BooWidget(int id)
{
//any model, any partial
}
}
Each method in your controller is single purpose, has a distinct signature and does one thing, no conditions to pass in and no decisions required.

How to get view name in controller while navigating from view to controller in MVC3

I have below view in my project,
PolicyScreen.cshtml
The above view has below control,
#Html.ActionLink("OK", "AccountScreen", "AccountUC", new { id= ViewBag.id})
Account controller looks like below,
[ActionName("AccountScreen")]
public ActionResult GetPolicyController(int id)
{
if (viewName='PolicyScreen')
{
//do validation
}
}
If I click OK, I am able to hit AccountUC controller and AccountScreen Action Name properly.
Now I need to know from which view I was navigated to AccountUC controller?
The answer is PolicyScreen, but I don't know how to get this view name in action method,any help?
I wonder why you need this, but you can do this by putting the view name in the action link parameters:
new { id = ViewBag.id, fromView = "PolicyScreen" }
And of course you'll need to alter your action method's signature:
public ActionResult AccountScreen(int id, string fromView)
If you want to get the view name automatically rather than hardcode it, see Retrieve the current view name in ASP.NET MVC?.
If you want the action name rather than the view name, see Get current action and controller and use it as a variable in an Html.ActionLink?.
Try this
#Html.ActionLink("OK", "AccountScreen", "AccountUC",
new { id= ViewBag.id , viewName="replaceCurrentViewNameHere"},null)
Make sure your action method has a parameter to accept the viewname we are sending
[ActionName("AccountScreen")]
public ActionResult GetPolicyController(int id,string viewName)
{
if (viewName=='PolicyScreen')
{
//do validation
}
}

How to specify a RedirectToRouteResult

My existing MVC code contains an action routine something like this:
[HttpPost]
public ActionResult Register1(SomeViewModel model)
{
return RedirectToAction("Register", new { p = model.PageNumber - 1 });
}
I want to move this code to a library routine:
public static ActionResult ProcessPost(Controller controller, string action,
int pageNumber)
{
// Redirect to the specified action on the specified controller
return new RedirectToRouteResult( <something here> );
}
and call it from the action routine like this:
return ProcessPost(this, "register", model.PageNumber);
Can some kind person give me the <something here> code that yields an ActionResult that redirects to the specified action (specified by the string argument) on the specified Controller (specified by the Controller argument?
Taking a look at the documentation on RedirectToRouteResult seems pretty straight forward:
var routeValues = new RouteValueDictionary();
routeValues.Add("Action", action);
routeValues.Add("Controller", controller.GetType().Name);
routeValues.Add("PageNumber", pageNumber);
var result = new (RedirectToRouteResult(routeValues);
After some experimentation, this appears to be a simple solution:
return new RedirectResult(controller.Url.RouteUrl(
new { action = action, p = pageNumber }
));
Apparently, the Url method on a specific Controller instance is smart enough to use that instance to get the controller name part of the full URL.

Resources