I want to be able to call a page the in following way:
www.mydomain.com/articles/article-name-with-hyphens
I tries the following:
public class ArticlesController : Controller
{
[ActionName("article-name-with-hyphens")]
public ActionResult ArticleNameWithoutHyphens()
{
return View("~/Content/Views/Articles/ArticleNameWithoutHyphens.cshtml");
}
}
However, I receive this message:
The view '~/Content/Views/Articles/ArticleNameWithoutHyphens.cshtml'
or its master was not found or no view engine supports the searched
locations. The following locations were searched:
~/Content/Views/Articles/ArticleNameWithoutHyphens.cshtml
P.S. If I change the code to the regular way:
public class ArticlesController : Controller
{
public ActionResult ArticleNameWithoutHyphens()
{
return View("~/Content/Views/Articles/ArticleNameWithoutHyphens.cshtml");
}
}
And call:
www.mydomain.com/articles/ArticleNameWithoutHyphens
I get the desired page.
Where is my problem?
Did you try with Route attribute?
[RoutePrefix("Articles")]
public class ArticlesController : Controller
{
[Route("article-name-with-hyphens")]
public ActionResult ArticleNameWithoutHyphens()
{
return View("~/Content/Views/Articles/ArticleNameWithoutHyphens.cshtml");
}
}
Therefore you can query like -
localhost/MyApp/Articles/article-name-with-hyphens
This perfectly works with MVC5.
Related
I have a controller called BaseController. In the BaseController, I have an Action method called Index which has some logic that involves querying the routes and building the URLs. Something on the lines of:
var link = Url.RouteUrl("myroute", new { id = 5 });
All this is well and fine until I create a controller NewController that extends the BaseController. In the constructor of NewController, I pass BaseController as a dependency.
public class NewController
{
private BaseController _baseController;
public NewController(BaseController baseController)
{
_baseController = baseController;
}
public ActionResult Index()
{
return _baseController.Index();
}
}
Reason why this was needed was because I need to override the view (some HTML and CSS changes). I didn't want to recreate the models and services and rewrite the business logic, so thought this would be the best and most time-effective approach.
Only issue is when the BaseController's Index Action is called, the Url is null obviously. Routes data is not available because the request was generated outside the base controller.
What is the best way to get around this?
Make BaseController.Index() virtual:
public class BaseController : Controller
{
public virtual ActionResult Index()
{
return View();
}
}
Then use inheritance:
public class NewController : BaseController
{
public override ActionResult Index()
{
var index = base.Index();
//do whatever
return index;
}
}
You are trying to call action method from another controller. Propably your constructor method gets baseController as a null. can you try to implement it like following
public ActionResult Index()
{
return new BaseController().Index(); // assume you call index action
}
Or you can call BaseController action from another controller like following
public ActionResult Index()
{
return RedirectToAction("Index", "Base"); // assume you call index action
}
You can also change Route url like following.
#Url.RouteUrl("myroute", new { controller = "Base", action = "Index", id = 5 })
I have another solution that requires a little bit of code design efforts.
Why don't you Abstract your business logic away from the two Controllers?
For example: RouteBuilder.cs a class that have the functions that contains the logic of building the routes.
And BaseClass.cs is a class that contains the Logic shared between the two Controllers.
Then:
public class BaseController
{
public ActionResult Index()
{``
//Instantiase BaseClass.cs and call the needed functions. Then RouteBuilder.cs and call functions.
return View();
}
}
public class NewController
{
public ActionResult Index()
{``
//Instantiase BaseClass.cs and call the needed functions.
return View();
}
}
Viola. Problem solved and clean code produced.
I have an ASP.NET MVC 4.5 app. In this app, I have two controllers: Parent and Children. The look something like this:
[RoutePrefix("dashboard/parents")]
public partial class ParentsController : Controller
{
public ActionResult Index()
{
return View();
}
[Route("add")]
public ActionResult Add()
{
return View();
}
}
[RoutePrefix("dashboard/children")]
public partial class ChildrenController : Controller
{
public ActionResult Index()
{
return View();
}
[Route("add")]
public ActionResult Add()
{
return View();
}
}
At this time, these controllers work how I want. However, in my ChildrenController, I want to add something like an overload to the add route. In other words, I'd like for the user to be able to visit: /dashboard/parents/{parentId}/children/add. This URL would be used to add a child to a specific parent. My question is, how do I update my controllers to allow for this type of scenario?
thank you!
I think what you are looking for the is "~" to override your default routeprefix.. The following example is taken from the asp.net website which tells you how to accomplish the task.
[RoutePrefix("api/books")]
public class BooksController : ApiController
{
// GET /api/authors/1/books
[Route("~/api/authors/{authorId:int}/books")]
public IEnumerable<Book> GetByAuthor(int authorId) { ... }
// ...
}
When I try to redirect to custom URI Scheme like: openURL://, the web browser directs me to a relative path: http://localhost/myServer/Main/openURL instead of displaying openURL://.
My code:
public class MainController : Controller
{
public ActionResult MyAction()
{
return Redirect("openURL://");
}
}
I also used :
public class MainController : Controller
{
public ActionResult MyAction()
{
return new RedirectResult("openURL://");
}
}
but it did not work.
Provide a fully qualified URL :-
Instead of
return Redirect("www.google.com");
Use
return Redirect("http://www.google.com");
Edit :- As per your updated question,
check these stackoverflow posts 1 , 2 , 3.
Is it "legal" to have a controller inherit a route from its BaseController ? It seems it's not allowed for Attribute Routing , but how about normal route registration via RouteCollection?
The reason is I currently have a bunch of controllers, each representing some kind of file converter. Each of them has a common set of methods to upload the file to be converted. These method are endpoints on each controller not just private methods. I'd like for the following routes to be valid:
/api/controller1/uploadfile
/api/controller2/uploadfile
/api/controller3/uploadfile
Can I get an example how this could be done inside a BaseController and if it's not possible, an alternative.
Here's what works:
public abstract class BaseUploaderController : ApiController
{
[HttpGet, Route("uploadfile")] //Needs both because HttpGet("uploadfile") currently only supported in MVC attribute routing
public string UploadFile()
{
return "UploadFile";
}
}
[RoutePrefix("api/values")]
public class ValuesController : BaseUploaderController
{
[Route("{id:int}")]
public string Get(int id)
{
return "value";
}
}
Are you looking to place this UploadFile action in the base controller and other controllers inheriting from them should still be able to hit UploadFile from their respective routes like you mentioned in your post? If yes, you could create an abstract base api controller and place this UploadFile action in it and your requests to the individual controllers should work as expected.
Example:
public abstract class BaseApiController : ApiController
{
// POST /api/Values
// POST /api/Test
public string UploadFile()
{
return "UploadFile";
}
}
public class TestController : BaseApiController
{
// GET /api/test/10
public string GetSingle(int id)
{
return "Test.GetSingle";
}
}
public class ValuesController : BaseApiController
{
// GET /api/values/10
public string GetSingle(int id)
{
return "Values.GetSingle";
}
}
As per this answer https://stackoverflow.com/a/21610390/122507 attribute routes are not inherited.
I am currently debating between introducing unnecessary method in 30 controllers just so I can add an attribute route or add a fake parameter to the base class method to let the default routing disambiguate between Get(int id) and GetHistory(int id, bool history) where I don't need the second parameter.
I have a project that has a 'core' version, and a 'customised' version.
They are separate projects.
'customised' inherits functionality from 'core' and in some case overrides methods.
For example:
I have a user model that looks like this:
public class User
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
Then, in a separate assembly,
public class User : Core.User
{
public string CustomProperty { get; set; }
}
I then have a controller (in my 'core' assembly)
public class UserController : Controller
{
[HttpPost]
public ActionResult SaveUser(User user)
{
}
}
In my other project, I have a UserController that inherits from Core.UserController:
public class UserController : Core.UserController
{
[HttpPost]
public ActionResult SaveUser(Custom.User user)
{
}
}
Obviously, in my Global.asax I have the controller namespaces mapped
However, when I hit the SaveUser method, I get
The current request for action SaveUser on controller type
UserController is ambiguous between the following action methods
While I understand the problem, is there any way around this?
In a nutshell:
I want to use Core.UserController methods most of the time, but in this instance, I need to use my Custom.UserController SaveUser method (since it takes my Custom.User type)
Polymorphism?
public class UserController : Controller
{
[HttpPost]
public virtual ActionResult SaveUser(User user)
{
}
}
public class UserController : Core.UserController
{
[HttpPost]
public override ActionResult SaveUser(User user)
{
var customUser = user as Custom.User;
if(customUser != null)
{
//Your code here ...
}
}
}
Another possible workaround if the polymorphism solution doesn't work or isn't acceptable, would be to either rename your UserController or its action method to something slightly different:
public class CustomUserController : Core.UserController
{
[HttpPost]
public ActionResult SaveUser(Custom.User user)
{
}
}
public class UserController : Core.UserController
{
[HttpPost]
public ActionResult SaveCustomUser(Custom.User user)
{
}
}
If you wanted to keep the routes consistent with the other project, you would just have to create a custom route for this.
I encountered the same problem in my own project today and came across your post.
In my case, while I didn't want to alter the way the core controller's logic functioned, I was able to make changes to its code, and thus its modifier keywords. After adding virtual to the base controller's actions, and override to my derived controller's actions. The original controller's actions still function, my derived controller uses my customized actions, no more ambiguous errors.
I realize you may not be able to modify your Core controller, and if this is the case, then you need to differentiate your actions using some other means. Action name, parameters or some other solution such as a custom implementation of ActionMethodSelectorAttribute. That was my first attempt at this problem, but before I got too far down that path of how to implement it, I discovered the virtual/override solution. So I don't have code to share on that route unfortunately.