Using optional parameters in Umbraco 7 Urls - umbraco

Am new to using Umbraco. I need to create Urls with an an optional parameter on the end e.g.
mysite.com/people/john
mysite.com/people/jane
etc
however by default Umbraco appears to require a separate page for each person. Is there a built method in Umbraco that will allow me to define the last part of the Url as an optional parameter or do I have to write a custom route for it?
Thanks

You have a couple of options here.
Use IIS URL Rewriting to rewrite your URLs under the hood and rewrite /people/john to /people/?person=john say. Then you can pick up the person from the query string on the page.
Write a custom URL Finder that looks for the URLs and does some stuff under the hood, like get the people page, and then set a context item with the person name in for you to use in your views etc.
You could write a custom route for it. Custom routing in Umbraco is slightly different to in normal MVC. Here is a blog post detailing how you can do it: http://shazwazza.com/post/custom-mvc-routes-within-the-umbraco-pipeline/

Related

#Url.Action("Action", "Controller") returns "/cgi-bin?action=Action&controller=Controller"

For some reason it thinks the target is an Apache server - I suspect?
The MVC is V5.2.3 and its dependancies are correct as per nuget
. I have searched and searched to no avail.
EDIT
The code is simply #Url.Action("Action", "Controller")
So I created a brand new MVC project and using exactly the same code the correct code was returned.
http://localhost:53143/Controller/Action
EDIT 2
I removed my web.config files as the problem is not there.
I got in touch with an expert and he looked at the project and answered as below.
(BTW I have 'cgi-bin' in a route as there are old URLs out in the wild that relate to my domain previously being hosted on an Apache server and which I cannot change.)
The answer
I digged a little more into the source code of the mvc helpers and, yes, the two issues (I had a similar problem Html.BeginForm with overload causes form action to be '/cgi-bin?action=Index&controller=Home' and so the HomeController is bypassed) are related since Url.Action and Html.BeginForm boil down to calling one and the same method: UrlHelper.GetUrl... Now, what this method does is:
Retrieve the current URL including controller, action, area...
Add or replace the parameter(s) you specify,
Find the best matching route! <==
If there are any route variables - push the provided parameters into those variables.
Stick the rest of the parameters into the query string <==
I have deliberately highlighted point 3 & 5, with point 3 being the most important. So, UrlHelper.GetUrl (and Url.Action and Html.BeginForm respectively) needs a route and it searches through the available ones to find the first match.
Now, here comes the problem with your mixed webforms-mvc app - an issue which is not present when you are dealing purely with MVC: You are using MapPageRoute!!! Please, note that it is different from MapRoute. And MapPageRoute uses the PageRouteHandler class to create the route whereas MapRoute uses the MvcRouteHandler class and it makes all the difference because PageRouteHandler creates the route in such a way that it's always a good match for UrlHelper.GetUrl("ActionName", "ControllerName") with the action name and controller name being thrown into the query string as parameters (point 5).
So, what happens with your set-up is that Url.Action is searching for a route and is hitting the first one created by MapPageRoute and in your case this is:
routes.MapPageRoute("cgi-bin", "cgi-bin/{*theRestcgi-bin}", "~/home/Search.aspx");
That's where that arcane cgi-bin part of the query string comes from, giving the impression that the framework is actually searching for some virtual/physical folder.
As for the proper solution: either define a suitable route or specify the url as a simple string the way you have done. I think, your solution is the better one as you won't have to move around the route definitions in the RouteConfig class.

Umbraco - Dynamic Pages

I was hoping someone might be able to give me some help with what I am planning to do...
I want to create a dynamic "City.aspx" page that accepts a url parameter and dynamically generates a page based on that particular city.
For example, if someone called "City.aspx?city=london" then it would build a page with custom content relating to London and if someone called the page "City.aspx?city=manchester" it would build the page with content relating to Manchester.
I have looked into building the sitemap and UrlRewriting and am pretty sure i can redirect to this new page with a parameter but have no idea what I need to do next.
Can anyone help please?
Thanks
TaxiRoute
I would recommend that you create url's like /city/london/1234 where the last part is the ID of your document.
By using the built-in UrlRewrite function in Umbraco, you can make the url be internally rewritten to /city.aspx?name=london&id=1234
In the /config/Urlewriting.config you can add rewrite rules.
For the above you need something like this:
<add name="city_rewrite"
virtualUrl="^~/city/(.*)/(.*)"
rewriteUrlParameter="ExcludeFromClientQueryString"
destinationUrl="~/city.aspx?name=$1&cityid=$2"
ignoreCase="true" />
Once you have this sorted out, you can use the following code in your code-behind off the City.aspx Macro to get the corresponding Document.
// get the city Document Id from the querystring
string cityID = HttpContext.Current.Request.QueryString["cityid"];
if (!string.IsNullOrWhiteSpace(cityId))
{
// get the cityNode
Node cityNode = new Node(cityId);
// do whatever you want with this node, like display it's data
}
This is a .NET Macro, but of course you can do the same with XSLT or Razor-code.
If you have the information outside of standard Umbraco content that is dynamic for each city, then simply write a macro or macros (or partial views?) to get the dynamic data via that "city" get parameter. Then you can use UrlRewriting to make URLs look like standard web pages (/city/london.aspx). UrlRewriting will make that URL appear to the server as though it was this: /city.aspx?city=london. (http://our.umbraco.org/wiki/reference/packaging/package-actions/community-made-package-actions/add-an-url-rewrite-rule)
In your macros you can either pass the "city" get parameter to the macro(s) as a macro parameter via bracket syntax (http://our.umbraco.org/wiki/reference/templates/umbracomacro-element/macro-parameters/advanced-macro-parameter-syntax). Or your can just get the city parameter via request variables (razor) or Umbraco.library (XSLT).

Create external link in Asp.Net MVC3

I know there are a lot of utility and helper classes/methods for generating URLs and links from internal routes and controllers. But how would you tackle the below in MVC 3?
In a razor file someone has defined this:
Website
ExternalURL in this instance will hold values like www.yoursite.com, without any prefixes. Hard-coding an http:// at the start is an obvious no-no but how best to handle this?
It's not so bad to hardcode http:// in your case, but if you want to avoid it, I see few options, but maybe most correct will be to extend your model with property #Model.Details.ExternalUrlLink or something like that. In getter you can do any logic what you want over original value, e.g. concatenate http:// prefix if it's not presented

how to remove sitecore folder name in the url?

I created a sitecore year/month/day folder structure in the content tree, when i view each article under the folder node, the url could be http://local/landing/year/month/day/article1.aspx, how could I make the url like this: http://local/landing/article1.aspx?
just remove the year/month/day structure in the url.
Is there some function in sitecore like remove or hide special templates in the frontend url ?
Any help , Thanks .
You can do it in 2 ways:
Use IIS 7 Url rewrite module to change the url. This way the url will be rewritten before it gets to sitecore and you don't need to change any code. You can find more info at the iis website
You can create a custom Item resolver and add it to the RequestBegin sitecore pipeline. Alex Shyba wrote about it here.
It sounds like you may have thousands of these items, but even so, you may want to use the built in functionality of Sitecore and consider creating aliases for each of these items. Programmatically creating an the alias on an ItemSaved event or ItemCreated is probably easiest.
As #marto and #seth have said, you can use URL rewriting or aliases to solve this.
There is, however, a drawback to doing this, irrespective of how you choose to do it.
If you have very many items (your structure makes it sound like you may do) then either method will require that the URL is unique. Removing the date structure from the URL means that all items in your landing section will require unique URLs (whether inherited from their item names or by some other means). This can impact on SEO for your site, as authors may have difficulty finding an unused name that is also human readable and good for SEO. It's unlikely you want to use ugly GUIDs in your URLs.
2 options
Change Bucket configuration and the set the required folder structure, bucket configuration can be found in Sitecore.Buckets.config file
Extend GetFromRouteValue Item Resolver and overwrite the ResolveItem() method to get the bucket item.
The default GetFromRouteValue class reference can be found in Sitecore.MVC.config file and replace this with your own customized implementation.
We have implemented with customized routing and getting the exact item if the route path matches.
Thanks,
Jisha

What is the simplest way to return different content types based on the extension in the URL?

I'd like to be able to change the extension of a url and recieve the model in a different format.
e.g. if
/products/list
returns a html page containing a list of products, then
/products/list.json
would return them in a json list.
Note: I like the simplicity of the ASP.NET MVC REST SDK, it only requires about 5 lines of code to hook it in, but the format is specified as a query string parameter i.e. /products/list?format=json which is not what I want, I could tweak this code if there are no other options, but I don't want to reinvent the wheel!
I wrote a blog post that shows one possible example. It's a tiny bit complicated, but might work for your needs.
http://haacked.com/archive/2009/01/06/handling-formats-based-on-url-extension.aspx
You should be able to just use routes in conjunction with the rest sdk
If you have the flexibility to drop Apache or something similar in front of your service, you can always use mod_rewrite to rewrite an external http://products/list.json into http://products/list?format=json which your framework can render more easily.
Instead of "list.json", you could choose "list/json" and use a route like
{controller}/{action}/{id}
Then ProductController.List would be called, with an ID parameter of "json". The .List() action then would decide whether or not to return an HTML view or JSON content.

Resources