I have an asp.net Webforms website that I'm trying to integrate MVC to. I'm almost there, but I'm having some problems.
What I did so far:
Added references to:
System.Web.Routing
System.Web.Abstractions
System.Web.Mvc
Updated the root Web.config to load the three assemblies at run time.
Added directories:
Views
App_Code\Controllers
Updated the Global.asax and configured routing:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
}
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.IgnoreRoute("{resource}.aspx/{*pathInfo}");
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = "" }
);
}
So far so good.
I right-click the Controllers folder, add a "HomeController", like this, run the website and it works!
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
public class HomeController : Controller
{
public string Index()
{
return "This is my <b>default</b> action...";
}
public string Welcome()
{
return "This is the Welcome action method...";
}
}
Now the problem:
I update the HomeControler to use a View, like this, but it doesn't work.
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
}
To create the view, I created a directory inside "Views" called "Home". Inside "Home" I added a new "Empty Page (Razor v3)", called "Index.cshtml":
#{
Layout = "~/Views/Shared/_Layout.cshtml";
}
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>View Template!</p>
The first problem is with this line:
ViewBag.Title = "Index";
VS indicates that "The name 'ViewBag' does not exist in the current context
The second problem is that when I run the website, I get the following error message:
The view 'Index' or its master was not found. The following locations
were searched: ~Views/Home/Index.aspx ~Views/Home/Index.ascx
~Views/Shared/Index.aspx ~Views/Shared/Index.ascx
I know it is possible to integrate a Webforms website with MVC pages.
It appears like my configuration is correct. I can successfully add a Controller and get the desired result.
BUT, how do I get my Controller to use a View?
Related
I am using 2017 VC for mac, the xamarian version of vs does not have the auto Areas Mapper. I manually added Areas folder and configured the routing properly, when I add an actionLink to my main csHTML page it is throwing an 500 error and stating.
System.InvalidOperationException
The view 'Billing' or its master was not found or no view engine supports the searched locations. The following locations were searched:
~/Views/BillingMain/Billing.cshtml
~/Views/BillingMain/Billing.vbhtml
~/Views/Shared/Billing.cshtml
~/Views/Shared/Billing.vbhtml
~/Views/BillingMain/Billing.aspx
~/Views/BillingMain/Billing.ascx
~/Views/Shared/Billing.aspx
~/Views/Shared/Billing.ascx
Instead it should be searching in ~/Areas/Billing/Views/BillingMainController.cshtml
I have tried everything to get this to work, but only keep on getting stuck.
Here is my directory hierarchy
Project-
AppStart-
Areas-
Billing-
Invoice-
Controllers-
Scripts-
Views-
Global.asax
I am only testing Billing area for now, below is the rest of my code.
RouteConfig
using System.Web.Mvc;
using System.Web.Routing;
namespace WORK_GODDAMN
{
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
//AreaRegistration.RegisterAllAreas();
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
//,namespaces: new string[] { "WORK_GODDAMN.Areas.Controllers" }
);
}
}
}
BillingAreaRegistration.cs
using System;
using System.Web.Mvc;
namespace WORK_GODDAMN.Areas.Billing
{
public class BillingAreaRegistration : AreaRegistration
{
public override string AreaName
{
get
{
return "Billing";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Billing_Default",
"Billing/{controller}/{action}/{id}",
new {controller = "BillingMain", action = "Index", id = UrlParameter.Optional }
, namespaces: new string[] { "WORK_GODDAMN.Areas.Billing.Controllers" }
);
}
}
}
Global.asax
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using System.Web.Http;
namespace WORK_GODDAMN
{
public class Global : HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RouteConfig.RegisterRoutes(RouteTable.Routes);
GlobalConfiguration.Configure(WebApiConfig.Register);
}
}
}
main _Layout.cshtml this is where the Action Link redirects and believe I might be doing something wrong here, but at this point I have no clue what could be causing the problem.
<!DOCTYPE html>
<html>
#using System.Web.Optimization
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>#ViewBag.Title</title>
#Scripts.Render("~/Scripts/modernizr.js")
</head>
<body>
<div>
<div>
<h2>{Demo}- Pluggable Modules</h2>
</div>
<div id="nav">
#Html.ActionLink("Home","Index","Home", new {Area=""}, null)
#Html.ActionLink("Invoice","Index","InvoiceMain", new {Area=""}, null)
#Html.ActionLink("Billing","Index","BillingMain", new {Area=""}, null)
</div>
<hr />
<div>
#RenderBody()
</div>
</div>
#Scripts.Render("~/Scripts/jquery.js")
#RenderSection("Scripts", required: false)
</body>
</html>
Figured it out, it was in my controller that the error was happening. Instead of returing return View("Index") I just gave the absolute path return View("~/Areas/Billing/Views/Index.cshtml") which is sort of a work-around, which is the only thing I found would work.
Also in the future if anyone wants to use html action link and model tags, you will need to manually add Web.Config file in both Areas/{area}/Views and Areas folder so you can use MVC framework in your cshtml View file. THIS IS FOR ANYONE WHO HAD TO MANUALLY CREATE AREAS if you use VS tool to add->Areas VS will automatically generate required files if you have VS do it, since Im using Mac Xamarin VS I don't have that convenient option.
This is what I had to change.
In {Project/Areas/Billing/Views/Index.cshtml} Change
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Ajax;
namespace WORK_GODDAMN.Controllers
{
public class BillingMainController : Controller
{
// GET: Billing/BillingMain
public ActionResult Index()
{
return View("Index");
}
}
}
TO
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Ajax;
namespace WORK_GODDAMN.Controllers
{
public class BillingMainController : Controller
{
// GET: Billing/BillingMain
public ActionResult Index()
{
return View("~/Areas/Billing/Views/BillingMain/Index.cshtml");
}
}
}
Assuming your have BillingMain controller inside the Billing area, you should explicitly specificity the area name when using the ActionLink.
#Html.ActionLink("Billing","Index","BillingMain", new {Area="Billing"}, null)
This will generate the link with href value pointing to yourSiteBaseAddress/Billing/BillingMain/Index
Assuming you do not have any customer route definitions to override the default conventions, it should work as long as you have the view file Index.cshtml in ~/Areas/Billing/Views/BillingMain/ or ~/Areas/Billing/Views/Shared/ (Assuming you are not trying to return a different view file from the Index action)
Specify the name of area in Html.ActionLink.
#Html.ActionLink("Billing", "Index", "BillingMain", new { Area = "Billing" }, null)
When I try to make a new view in an area in MVC 6 it only displays a white page. The Home/Index action works fine, and this one will hit the controller but never displays the view. I can return content and get a display, but when I try to return the view it breaks. Any advice?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNet.Mvc;
using PmData.Models;
// For more information on enabling MVC for empty projects, visit http://go.microsoft.com/fwlink/?LinkID=397860
namespace PlantManagement.Areas.Cms.Controllers
{
[Area("Cms")]
public class AssetsController : Controller
{
// GET: /<controller>/
public IActionResult Index()
{
return View();
}
}
}
that is coupled with a blank view that calls to the main layout page.
I found the issue. Sadly, it's because I'm so new to MVC 6 / vNext so I feel silly. It was a matter of their being an issue with an item on the page, but without app.UseDeveloperExceptionPage(); being added in the configure of startup.cs it would never show me the actual error, just give me the generic 500 error and white page. Once I added that it started producing errors I could work with and gave me what I needed.
I had a similar issue, and resolved it by,
a) Create a _ViewStart.cshtml file in each area you have. i.e. Areas/Cms/Views/_ViewStart.cshtml
b) In this _ViewStart.cshtml file add
#{
Layout = "~/Areas/Cms/Views/Shared/_LayoutCms.cshtml
}
c) Add a _LayoutCms.cshtml to Areas/Cms/Views/Shared
d) In this file add the reference to the overall site layout
#{
Layout = "~/Views/Shared/_Layout.cshtml
}
and any other area specific layout code.
That fixed my blank page issue. Hopefully yours too
In addition to my last answer, try these steps
e) Make sure you have an area registration setup within your Cms area folder i.e Areas/Cms/CmsAreaRegistration.cs
public class CmsAreaRegistration : AreaRegistration
{
public override string AreaName
{
get
{
return "Cms";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Cms_default",
"Cms/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
}
}
f) In your App_Start/RouteConfig.cs make sure you are registering all areas by adding AreaRegistration.RegisterAllAreas() something like the following.
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
AreaRegistration.RegisterAllAreas(); //Add this//
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
I'm trying to use route attributes in MVC 5. I created an empty MVC project in Visual Studio to experiment with and so far I can't get the routing to work. I'm using this page as a reference. I have the latest assemblies and updated all NuGet packages to their latest versions.
Here's my code:
// RouteConfig.cs
namespace MvcApplication1
{
using System.Web.Mvc;
using System.Web.Routing;
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
// Enables MVC attribute routing.
routes.MapMvcAttributeRoutes();
// The default route mapping. These are "out of the bag" defaults.
routes.MapRoute(null, "{controller}/{action}/{id}", new
{
controller = "Home",
action = "Index",
id = UrlParameter.Optional
});
}
}
}
// TestControler.cs
namespace MvcApplication1.Controllers
{
using System.Web.Mvc;
public class TestController : Controller
{
public ContentResult Output1()
{
return Content("Output 1");
}
[Route("Test/Output2")]
public ContentResult Test2()
{
return Content("Output 2");
}
}
}
#* Index.cshtml *#
#Html.Action("Output1", "Test")
#Html.Action("Output2", "Test")
The Output1() method renders properly. However, when Output2() is rendered, I get the error "A public action method 'Output2' was not found on controller 'MvcApplication1.Controllers.TestController'."
Your action is named Test2 not Output2. Change the following
#Html.Action("Test2", "Test")
This is because #Html.Action will not actually use routing. With it you explicitly specify actions and controllers.
The routing will be used when someone for instance makes the http://example.org/Test/Output2 request from a browser.
It is my understanding that child actions execute using the same routes as the parent actions but I am having difficulty getting this to work. I have an MVC5 application that incorporates several areas. In one area I want to display a partial with some data in every view that is separate from the controller model so I added a child action to accomplish this, but when I try to view any of the pages in that area I get an InvalidOperationException telling me that
No route in the route table matches the supplied values
The area controller looks like this (simplified for brevity):
[RouteArea("SomeArea")]
[RoutePrefix("Here")]
public class PageController : Controller
{
private readonly IRepository repository;
public PageController(IRepository Repository)
{
this.repository = repository;
}
[Route("Page")]
public ActionResult ShowPage(int pageNumber = 1)
{
var model = new PageViewModel(repository, pageNumber);
ViewBag.Title = "This is a Page";
return View("ShowPage", model);
}
[ChildActionOnly]
public PartialViewResult DataView()
{
var model = new DataViewModel(repository);
return PartialView("DataView", model);
}
}
The layout for the area:
#{
Layout = "~/Views/Shared/_Layout.cshtml";
}
#Scripts.Render("~/bundles/pages")
<body>
<div id="content">
<br />
#Html.Partial("~/Areas/Page/Views/Shared/Search.cshtml")
#RenderBody()
#Html.Action("DataView", "Page")
</div>
</body>
The route config:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapMvcAttributeRoutes();
AreaRegistration.RegisterAllAreas();
routes.MapRoute("Default",
"{controller}/{action}/{id}",
new {controller = "Home", action = "Index", id = UrlParameter.Optional}
);
}
I have tried catching unhandled routing exceptions as in this article by David Boike to no avail.
Any suggestions would be greatly appreciated at this point. Thanks
Answer, supplied by Kiran in the comment above, is to simply decorate the child action with the route value for that action. Thank you Kiran!
I spent an ungodly amount of time researching this, and getting frustrated while I was at it, for such a simple solution. The routing now works with the child action as below:
[ChildActionOnly]
[Route("DataView")]
public PartialViewResult DataView()
{
var model = new DataViewModel(repository);
return PartialView("DataView", model);
}
I'm using c#, visual studio 2010. I'm new to MVC
I was supplied with a simple HTML page that I converted to an aspx view. I then added the controller.
The view directory is Views/150/Index.aspx. The issue is that when I go to add the controller, the class name is not allowed to be a number.
namespace MyPages.Controllers
{
public class _50Controller : Controller
{
public ViewResult Index()
{
return View("Index");
}
}
}
When I entered the have the controller a number, it automatically changed it from 150 to _50. So I changed it to 150Controller.cs and changed the class name to 150Controller : Controller.
Unfortunately, you can't have a number as a class name, and _50Controller as the class name tries to direct to Views/_50/Index.aspx.
I would simply change the name, however I was specifically asked to have it as a number. I know I can set up a redirect in ISS... but is there another way to do this?
Thanks!
In C# members cannot start with a number. You could use routing in order to achieve that:
For example you could have the following controller:
public class ErrorController : Controller
{
public ActionResult Index()
{
return View("500");
}
}
which could be routed like this:
routes.MapRoute(
name: "Error",
url: "500",
defaults: new { controller = "Error", action = "Index" }
);
Now when you navigate to http://example.com/500 it will be the Index action of ErrorController that will get executed and which will render the 500.aspx view.