I was wondering how to setup routing in my MVC4 application where I can have a controller named TMZ and have it handle all of these routes:
/TMZ/About
/TMZ/Webinars
/TMZ/News
/TMZ/Conferment
/TMZ/CustomerCare
/TMZ/Marketing/Emails
/TMZ/Marketing/Brochures
/TMZ/Marketing/Print
/TMZ/Marketing/Press
/TMZ/Marketing/Presentations
/TMZ/Marketing/Graphics
/TMZ/Marketing/OCSRY
/TMZ/Marketing/Resources
/TMZ/Marketing/DesignStandards
/TMZ/Marketing/Videos
/TMZ/Marketing/PromoKits
/TMZ/Faculty/Forms
/TMZ/Faculty/Reports
/TMZ/CE/Guides
/TMZ/CE/Reports
/TMZ/Academy/Papers
/TMZ/Academy/Books
/TMZ/Academy/Promotions
/TMZ/ManualOfOperations
Showing Code:
Here is my RouteConfig.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
namespace LicenseeArchive
{
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute("TMZ",
"TMZ/{action}/{subaction}/{id}",
new { controller = "TMZ", action = "Index", subaction = UrlParameter.Optional, id = UrlParameter.Optional },
null,
new[] { "LicenseeArchive.Web.Controllers" });
routes.MapRoute("Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional },
null,
new[] { "LicenseeArchive.Web.Controllers" });
}
}
}
Here is my Global.asax.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
namespace LicenseeArchive
{
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
AuthConfig.RegisterAuth();
}
}
}
Here is my TMZController:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace LicenseeArchive.Controllers
{
public class TMZController : Controller
{
//
// GET: /TMZ/
public ActionResult Index()
{
return View();
}
public ActionResult About()
{
return View();
}
public ActionResult Marketing(string subaction)
{
string _view = "Index";
switch (subaction)
{
case "Brochures":
_view = "Marketing/Brochures";
break;
}
return View(_view);
}
}
}
And here is my View folder structure:
Views
Account
Login.cshtml
Manage.cshtml
Register.cshtml
Home
About.cshtml
Contact.cshtml
Index.cshtml
Shared
_Footer.cshtml
_Head.cshtml
_HeaderBlock.cshtml
_Layout.cshtml
_LeftAside.cshtml
_LoginPartial.cshtml
_TopNav.cshtml
Error.cshtml
TMZ
Academy
Books.cshtml
Papers.cshtml
Promotions.cshtml
CE
Guides.cshtml
Reports.cshtml
Faculty
Forms.cshtml
Reports.cshtml
Marketing
Emails.cshtml
Brochures.cshtml
Print.cshtml
Press.cshtml
Presentations.cshtml
Graphics.cshtml
OCSRY.cshtml
Resources.cshtml
DesignStandards.cshtml
Videos.cshtml
PromoKits.cshtml
About.cshtml
Conferment.cshtml
CustomerCare.cshtml
News.cshtml
ManualOfOperations.cshtml
Webinars.cshtml
_ViewStart.cshtml
Web.Config
The simplest way would be modify the "default" route in Global.asax.cs
routes.MapRoute("Default",
"{controller}/{action}/{subaction}/{id}",
new {subaction= UrlParameter.Optional, id = UrlParameter.Optional});
This would mean you could use the same url format in other Controllers as well. Your TMZController would look something like:
public class TMZController : Controller
{
public ActionResult About()
{
return View();
}
public ActionResult Marketing(string subaction)
{
return View();
}
}
Because the subaction/id are both optional you can construct 2, 3 or 4-part urls and just pickup the extra parameters in your actions, then handle them as required within the body of the methods.
routes.MapRoute("TMZ",
"TMZ/{action}/{id}",
new {controller = "TMZ", action = "Index", id = UrlParameter.Optional},
null,
new[] {"YourNamespace.Web.Controllers"});
routes.MapRoute("Default",
"{controller}/{action}/{id}",
new {controller = "Home", action = "Index", id = UrlParameter.Optional},
null,
new[] {"YourNamespace.Web.Controllers"});
In this case i assumed that you've a Controller named TMZ and in that controller you've set all other actions including Marketing, Academy, Faculty, CE
But here is two things important to consider
This route should be before the default route "as I put it here"
The Actions in the TMZController should have an string id parameter to handle the request. this id would be passed something like "Resources" for the Marketing action or "Books" for Academy Action.
Hope this was clear.
Related
I'm working on building a MVC4 web app and want to set specific URL I would like to use in the start point of my web application.
So I changed some values in RouteConfig.cs like this below.
routes.MapRoute(
name: "Default",
url: "{action}.mon/{id}",
defaults: new { controller = "login", action = "index", id = UrlParameter.Optional }
);
you may notify this, but I put a suffix after action name, so that I could invoke a controller, displaying the URL like " index.mon "
if I manually put "index.mon" after host address in URL bar, then it works just okay.
But when the app gets started automatically, it throws 403.14 error. ( "automatically start" means here that I ran this app by putting F5 key to run a temporary IIS server. )
the login controller looks like this
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Data.OleDb;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace Monarch815MVC.Controllers
{
public class loginController : Controller
{
//
// GET: /login/
public ActionResult index()
{
return View();
}
public ActionResult loginProcess(string id = "000000", string pass = "example", string scode = "co")
{
Dictionary<string, object> sessionData = null;
String SqlCommand = "USP_LOGIN";
DataSet UserInfo = dataController.ExecuteDataset(dataController.CONN_STRING, CommandType.StoredProcedure, SqlCommand, arParms);
if (UserInfo.Tables[0].Rows.Count > 0)
{
sessionData = new Dictionary<string, object>();
for (int i = 0; UserInfo.Tables[0].Rows[0].Table.Columns.Count > i; i++)
{
sessionData.Add(UserInfo.Tables[0].Rows[0].Table.Columns[i].Caption, UserInfo.Tables[0].Rows[0].ItemArray[i]);
}
}
return View();
}
}
}
( let's forget about the loginProcess, I took off a few codes. )
Do I have to do something on returning phase in index() or on Web.config? or, RouteConfig.cs?
I have to use the suffix ".mon" to invoke controllers with it.
I could think of solving this issue by only using a hack. You might want to create a dummy action which will be the default action and upon being hit will redirect the request to your index.mon
i tried following, Please check if this helps you. Thanks.
In the route config
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "DefaultY",
url: "{action}-mon/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
routes.MapRoute(
name: "DefaultX2",
url: "{action}/{id}",
defaults: new { controller = "Home", action = "Startup", id = UrlParameter.Optional }
);
}
In controller
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
public ActionResult Startup()
{
return RedirectToRoute("DefaultY", new {controller = "Home", action = "Index" });
}
}
For me i used index-mon. index.mon was not working (something which i'l explore later, perhaps it relates to static files), but above code demonstrates the approach.
Hope that helps.
I have one Hottowel project created using it's template from Visual Studio. I want to add the Web API feature in that project. I have created a Web Api controller to the controller folder and tries to access like "http://localhost:53397/api/Values" But I get an error saying The resource cannot be found error.
My controller code looks like below
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
namespace MvcApplication8.Controllers
{
public class ValuesController : ApiController
{
// GET api/<controller>
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
// GET api/<controller>/5
public string Get(int id)
{
return "value";
}
// POST api/<controller>
public void Post([FromBody]string value)
{
}
// PUT api/<controller>/5
public void Put(int id, [FromBody]string value)
{
}
// DELETE api/<controller>/5
public void Delete(int id)
{
}
}
}
I have the cs file in APP_start folder called BreezeWebApiConfig.cs which contains the logic to map the route like below.
GlobalConfiguration.Configuration.Routes.MapHttpRoute(
name: "BreezeApi",
routeTemplate: "api/{controller}/{action}"
);
Let me know If I am missing any configuration setting for Web APi.
Try to decorate your ApiController like bellow :
[BreezeController]
public class NorthwindIBModelController : System.Web.Http.ApiController {
readonly EFContextProvider<NorthwindIBContext> ContextProvider =
new EFContextProvider<NorthwindIBContext>();
[HttpGet]
public String Metadata() {
return ContextProvider.Metadata();
}
[HttpPost]
public SaveResult SaveChanges(JObject saveBundle) {
return ContextProvider.SaveChanges(saveBundle);
}
[HttpGet]
public IQueryable<Customer> Customers() {
return ContextProvider.Context.Customers;
}
For more information have a look to breeze documentation here.
Its seems like you are making a wrong Url Request. Look at your breeze route configuration for WebApi. You need to Pass like that http://localhost:53397/api/Values/Get as breeze is using Controller action based routing.
Hope this will help.
I'm trying to remove 'home' form my URL, so in other words:
www.domain.com/home/about/ becomes www.domain.com/aboutus
The problem is, the home is not being removed and I can't work out why. I can see others have identical questions with near identical answers as to mine here on on SO so I am at a loss why this won't work.
My Global.asax is
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Routing;
namespace Company.Ui
{
// Note: For instructions on enabling IIS6 or IIS7 classic mode,
// visit http://go.microsoft.com/?LinkId=9394801
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
}
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute("RemoveHomeUrl", // Route name
"{action}", // URL with parameters
new { controller = "Home", action = "Index" } // Parameter defaults
);
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
}
}
}
My ActionLink code is:
#Html.ActionLink("About us", "AboutUs", "Home", null, new { #class = "mega" })
When I hover over a link and when I click on the link, it still returns www.domain.com\home\aboutus
I'm running this in debug mode in Visual Studio 2012.
I am at a loss, can any one help?
I think you are working with your routes in the wrong place,
from the shown code it seems the registered routes are defined in RouteConfig class
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes); //routes are registered here
}
Try replacing
RouteConfig.RegisterRoutes(RouteTable.Routes);
with
RegisterRoutes(RouteTable.Routes);
or edit in the RouteConfig class
hope this helps.
I get "404 Not Found" on doing a Ajax call ,
maybe that I don't understand how routing works ...
function ApproveAlert(ID) {
$.ajaxPost('/api/DeviceApi/ApproveAlertNew', { 'ID': ID }, function (data) {
... get error "404 Not Found"
}, null);
}
in my mvc4 C# app I have a rout config :
RouteTable.Routes.MapHttpRoute(
name: "defaultapiaction",
routeTemplate: "api/{controller}/{action}"
);
RouteTable.Routes.MapHttpRoute(
name: "defaultapiid",
routeTemplate: "api/{controller}/{action}/{id}"
);
and apicontroller :
public class DeviceApiController : ApiController
{
//
// GET: /DeviceApi/
[HttpPost]
public bool ApproveAlertNew(int ID)
{
..do
}
Web API controllers don't use "Actions" in the same sense that MVC controllers do. Web API controllers also don't really use [HttpPost], [HttpGet] attributes either. They dispatch requests based on the names of the methods inside of the ApiControllers. I suggest to read up a little more on Web API differences from MVC as it is similar but sometimes hard to get up and running...
Here's some pretty generic examples from a Web API that I made for testing. I do not have JavaScript to post to this API because I was posting from a .NET WPF app. You would post to "/Important" NOT "/Important/Post" Hopefully this will get you on the right track...
WebAPIConfig.cs (Routes):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;
namespace ArrayTest.WebAPI
{
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
}
API Controller:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using ArrayTest.Models;
using System.Threading;
namespace ArrayTest.WebAPI.Controllers
{
public class ImportantController : ApiController
{
// POST api/important
public HttpResponseMessage Post(ImportantList values)
{
//manipulate values received from client
for (int i = 0; i < values.ImportantIDs.Count; i++)
{
values.ImportantIDs[i] = values.ImportantIDs[i] * 2;
}
//perhaps save to database, send emails, etc... here.
Thread.Sleep(5000); //simulate important work
//in my case I am changing values and sending the values back here.
return Request.CreateResponse(HttpStatusCode.Created, values);
}
}
}
Model:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ArrayTest.Models
{
public class ImportantList
{
public List<int> ImportantIDs { get; set; }
}
}
Can you try with:
function ApproveAlert(ID) {
$.ajax({
type: 'POST',
url: "/api/DeviceApi/ApproveAlertNew",
data: {
ID: ID
},
success: function (data) {
//Handle your success
},
error: function (jqXHR, textStatus, errorThrown) {
//Handle error
}
});
}
I have had it where the name/namespace/other attributes show up when sending a request, but now they have disappeared and cant figure out for the life of me what changed... I am trying to utilize the WebApi project but the documentation seems limited.
WebServiceResource.cs :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ServiceModel;
using System.ServiceModel.Web;
using wsDAL.EDataTypes;
using System.Data;
using System.IO;
using System.Text;
using System.Net.Http;
namespace wsDAL
{
[ServiceContract]
public class WebServiceResources
{
[WebGet(UriTemplate = "/GetNameValueTest/{name}/{value}")]
public NameValue GetNameValueTest(string name, string value)
{
NameValue nv = new NameValue("WS_" + name + "_WS", "WS_" + value + "_WS");
return nv;
}
}
}
GeneralResources.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Runtime.Serialization;
using System.Data;
namespace wsDAL.EDataTypes
{
[DataContract(Name = "NameValueContract", Namespace = "http://fred.NameValue.com")]
public class NameValue
{
private string _name;
private string _value;
public NameValue()
{
_name = null;
_value = null;
}
public NameValue(string Name, string Value)
{
_name = Name;
_value = Value;
}
[DataMember(Name = "NameMember")]
public string Name { get { return _name; } set { _name = value; } }
[DataMember(Name = "ValueMember")]
public string Value { get { return _value; } set { _value = value; } }
}
}
Note I am using lightcore as an IOC container (kinda new to this stuff)
Was originally going of the post at http://blog.alexonasp.net/post/2011/04/15/Microsoft-Web-API-e28093-the-REST-is-done-by-WCF-(Part-1).aspx
but once I got to part six where he is returning HttpResponseMessage<Contact> from POSTs, it all started falling apart. client was looking for the namespace when returning xml but that was not part of the serialized response...
Global.asax.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using LightCore;
using Microsoft.ApplicationServer.Http.Description;
using Microsoft.ApplicationServer.Http.Activation;
....
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
ContainerBuilder builder = new ContainerBuilder();
builder.Register<IResourceFactory, LightCoreResourceFactory>();
IContainer container = builder.Build();
var configuration = HttpHostConfiguration.Create().SetResourceFactory((serviceType, instanceContext, request) => container.Resolve(serviceType), null);
RouteTable.Routes.MapServiceRoute<WebServiceResources>("ws", configuration);
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
....
Ok, what it seems that I failed to realize, is that the name/namespace info gets serialized to the server, but not to the client.
Have you added a routing table record?
RouteTable.Routes.MapServiceRoute<WebServiceResources>("GetNameValueTest");
Updated answer on this... I was using a DataContractSerializer on the client which was adding the name/namespace info, while on the server I was using the default WebApi serialization which was not adding the info. Thanks for anyone who took time looking into this.