MVC route to content to avoid other routes from matching? - asp.net-mvc-5

In my MVC project I have a route like this:
routes.Add("MyRoute", new MyRoute("{controller}/{action}/{id}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }));
I also have some bundles (showing only constructor with URL here):
new Bundle("~/Scripts/companyname", typeof(JsMinify));
new Bundle("~/Content/themes/companyname/css", typeof(Microsoft.Web.Optimization.CssMinify));
new Bundle("~/Content/skin/css", typeof(Microsoft.Web.Optimization.CssMinify));
new Bundle("~/Content/companyname_css", typeof(Microsoft.Web.Optimization.CssMinify));
new Bundle("~/Content/print_css", typeof(Microsoft.Web.Optimization.CssMinify));
I want those bundles to not be matched by "MyRoute". How can I achieve that?

Found it. This is what RouteCollection.IgnoreRoute is for. I do find the documentation in this area pretty scarce, so I'll add a few details here.
routes.IgnoreRoute("Content/{*pathInfo}");
routes.IgnoreRoute("Scripts/{*pathInfo}");
Those lines tell the routing system to ignore URL:s that start with Content/ and Scripts/ respectively, and has "anything" after the /. The asterisk * in {*pathInfo} means that the pathInfo token should be assigned the remainder of the URL.
I have not been able to determine if the name pathInfo matters, or could be anything, but it appears that the pattern needs a placeholder there, with the leading asterisk, to match anything after the /.

Related

Yii2 Trailing Slashes in URL is breaking the route

I configured UrlManager in a project and It was working the way I wanted.
Now i tried to add a content whose name contains a trailing slash but i get an error 404 (Object not found).
For example:
www.test.com/article/detail/id_of_article/title_of_article
title_of_article = People are ... => Work
title_of_article = 1/3 of People are ... => Doesn't Work (Object not Found)
The Trailing Slash is breaking the Url although it is encoded in %2F
This is how i create url:
Html::a(Html::encode($model->title),
['article/detail', 'id' => $model->id, 'title' => $model->title])
I don't really know how I can deal with that.
For This , the best solution is to use slug names.
Instead of id and title, take one more field called slug_name in your database.
On Add or update of any record generate slug name and store in db.
For generating slug name, you can use custom function as below.
public function getSlugName($id,$title)
{
$slug=$id;
if(isset($title) && $title!=null)
{
// remove all spacea
$slug.='-'.str_replace(' ','-',strtolower($title));
}
$slug=preg_replace('/[^A-Za-z0-9\-]/', '', $slug); // Removes special chars.
$slug=str_replace(array('--'), '-', $slug); // remove multiple --
return $slug;
}
This function will return you uniq name. So you can use it in url.
This is also help in SEO.
Could be you need URL normalization
Since version 2.0.10 UrlManager can be configured to use UrlNormalizer
for dealing with variations of the same URL, for example with and
without a trailing slash.
NB by default UrlManager::$normalizer is disabled. You need to explicitly configure it in order to enable URL normalization.
see how here http://www.yiiframework.com/doc-2.0/guide-runtime-routing.html#url-normalization
There is an encodeParams property of UrlRule. Please try with that.

How to make optional params name in express route?

Here is below my code of route:-
app.get('/server/lead/get/:id?', leadCtrl.get);
app.get('/server/lead/filter/:filterQuery', leadCtrl.get);
As you see above i am using different route to access same controller method leadCtrl.get.
Now, i want something like route app.get('/server/lead/get/:id?:filter?', leadCtrl.get);. So, i can get params either req.params.id or req.params.filter but only one at a time.
What you asked in the question is not possible in the form that you describe it.
Now, i want something like route
app.get('/server/lead/get/:id?:filter?', leadCtrl.get);. So, i can get
params either req.params.id or req.params.filter but only one at a
time.
Your router would have no way to differentiate those two parameters. If it got a request to /server/lead/get/X then what is X? A filter or an ID?
Your options
You have few solutions here:
You can either keep using two routes like you did before.
You can use a common parameter for both cases as Robert explained in the comments.
Or you can use what seems to me the perfect solution for your use case - named query parameters - just use a route /server/lead/get and use query parameters to pass id and the filter.
Example URLs:
/server/lead/get?id=xxx
/server/lead/get?filterQuery=xxx
You will only have to make sure in your handler that only one of those two are set at a time with something like:
if (req.query.id && req.query.filterQuery) {
// respond with error
}
You can even mix the two if you have app.get('/server/lead/get/:id?') route you can have the id in the route and filterQuery as a query parameter. Now the URLs would be:
/server/lead/get/xxx (for id)
/server/lead/get?filterQuery=xxx (for filter)
For more info see: http://expressjs.com/en/api.html#req.query
Better way
If you follow some REST conventions then you can use:
app.get('/server/lead/:id') for one object with id (not optional)
app.get('/server/lead') for a list of objects (with optional filterQuery passed as a query parameter)
That way you would always know that when you access:
/server/lead/xxx - then it's one object with ID = xxx
/server/lead - then it's a list of any objects
/server/lead?filterQuery=xxx - then it's a list of objects that match the query
If you follow the REST conventions for things like this instead of inventing your own, it would be much easier for you to design the routes and handlers, and it would be much easier for other people to use your system.
You may also want to use plural /server/leads instead of /server/lead which is common with REST. That way it will be more obvious that leads is a list and leads/id is one of its elements.
For more info see:
https://en.wikipedia.org/wiki/Representational_state_transfer
http://www.restapitutorial.com/lessons/whatisrest.html
https://spring.io/understanding/REST
You have to realize that the following two routes match exactly the same:
app.get('/server/lead/get/:id?', leadCtrl.get);
app.get('/server/lead/get/:filter?', leadCtrl.get);
Express doesn't care about how you name the placeholders, so any requests for /server/lead/get/SOMEVALUE will always match the first (the one with :id).
You can add a distinction yourself, by only allowing a parameter to match a particular regular expression. From your code, it looks like :id should match MongoDB ObjectId's, so you can create a specific match for those:
app.get('/server/lead/get/:id([a-fA-F0-9]{24})?', leadCtrl.get);
If SOMEVALUE matches an ObjectId, it will call leadCtrl.get and populate req.params.id. If you also add another router for "the rest", you can also cover the req.params.filter case:
app.get('/server/lead/get/:filter?', leadCtrl.get);
As an aside: you're saying that you're passing JSON to the "filter" routes, in the URL. I would strongly suggest using a POST route for that, and post the JSON as request body content.

How to use add_rewrite_rule function, while permalink structure is disabled?

I am using the add_rewrite_rule() function to modify my URL structure.
I'm wanting to use add_rewrite_rule to add a custom rule but these rules only get added in when other than default settings are selected in my permalink settings area.
i.e. in the settings there are following options:
- Default http://localhost/wordpress/?p=123
- Day and name http://localhost/wordpress/2014/08/14/sample-post/
- Month and name http://localhost/wordpress/2014/08/sample-post/
- Numeric http://localhost/wordpress/archives/123
- Post name http://localhost/wordpress/sample-post/
- Custom Structure http://localhost/wordpress
So, when I select other then 'Default', my add_rewrite_rule() function works, but while selecting 'Default', the function doesn't seem to be work. So please suggest me how to work the function in any condition. Any help would be Appriciated.
Update:
I think the problem lies here:
When I use this, while selecting 'Default':
get_option('permalink_structure');
I got nothing.
While in the other cases, there are some values like:
/%postname%/
/archives/%post_id%
/%year%/%monthnum%/%postname%/
The Default permalinks, or so called "Ugly" permalinks, are not adding anything to the .htaccess file, so the Apache rewrite engine is not enabled. Without the rewrite engine, no rewrites can be done. So the short answer is that rewrites are not possible with Default permalinks.
I can recommend you to use rewrites along with query vars. When adding a rewrite rule, pass your custom data to a query var, and build the functionality around that query var. This way your functionality will work in all situations and with all permalink types.
So for example if you have the following rule:
add_rewrite_rule('^sometest/([^/]*)/?','index.php?custom_query_var=$matches[1]', 'top');
and you have the custom_query_var added as a query var by using the following code:
function add_query_vars_filter( $vars ){
$vars[] = "custom_query_var";
return $vars;
}
add_filter( 'query_vars', 'add_query_vars_filter' );
then when Default permalinks are selected, the following URL would work for you:
http://yoursite.com/index.php?custom_query_var=abc
and if "Pretty" permalinks are selected, the URL rewriting would work and your URL would look the following way:
http://yoursite.com/sometest/abc/
which is basically the best that can be achieved with rewrites.
I agree with #Martin. Here's a resource that will help https://core.trac.wordpress.org/ticket/15235
use this:
function my_add_query_vars( $qvars ) {
$qvars[] = 'business-coaching';
$qvars[] = 'country';
$qvars[] = 'territory';
$qvars[] = 'region';
return $qvars;
}
add_action('query_vars', 'my_add_query_vars');
//Write the rule
function add_analytic_rewrite_rule()
{
// Regex:The regex to match the incoming URL is:business-coaching(/([^/]+))?(/([^/]+))?(/([^/]+))?/?
// Redirect Rule :The resulting internal URL: `index.php` because we still use WordPress
// `pagename` or page_id=45 because we use this WordPress page
// `country` : we will assign the first captured regex part to this variable
// `territory` we will assign the second captured regex part to this variable
// `region` we will assign the third captured regex part to this variable
add_rewrite_rule('business-coaching(/([^/]+))?(/([^/]+))?(/([^/]+))?/?','index.php?page_id=45&country=$matches[2]&territory=$matches[`enter code `enter code here`here`4]&region=$matches[6]','top');//superfinal
}
add_action('init', 'add_analytic_rewrite_rule');

Rest API Architecture - GET a resource by alias

I need a help from you about REST Arch.
I've a resource and I can retrieve it with the classical GET /resource/ID URI, but this resource has an alias and someone want to GET this resource by calling it via alias.
There is a good way to do so by calling a GET /resource/?alias=x, take the ID and then go to the details /resource/ID.
Do you have any good idea about other ways to do this?
Thanks in advance
There is nothing wrong with a resource having two URIs (or two URIs pointing to the same resource, to put it another way). For example
GET www.myweatherapi.com/2013/11/18/rainfall
GET www.myweatherapi.com/today/rainfall
can both point to the same resource. You could say the latter is an alias of the former, or vice versa, it doesn't really matter, they both identify the same resource. You don't need to start explicitly labeling something as an alias of something else.
If the alias is temporary and may be gone in the future you could use the 307 response, temporary redirect. This tells the client that they should go to a different URI to find the resource, but not to assume that will be true in the future (eg limit how long you cache this).
As an aside, the client should not construct URIs, the server should return a content type format (HTML, JSON etc) that contains a way to identify the resources the client wants along with the URI of where to find them. For example a link in HTML saying "Todays Rainfall" with the URI to that resource. The user follows that link if they want todays rainfall
If you want to stay within the constraints of the REST architecture, you definitely need to stay with the verb GET. You can't add other methods.
Now you need to decide how the resource is named. You have a canonical name (your id), and an alias. One approach is to set up the controller for
GET /things/:id
so that :id can be either the canonical id or the alias. So you'd have
app.get('/resources/id', function (req, res) {
var id = req.params.id;
if (isAlias(id)) id = resolveAlias(id);
Thing.findById(id, null, function (err, thing) {
if (err) res.json(400, err)
if (thing === null) res.json(404, {"No such id": id})
res.json(thing)
});
});
You can also put in the alias as a query parameter, like you suggested.
I suspect the only other way might be to use a different url (somethng other than things) but I think this is disingenuous because you want to return the same representation whether or not you use the id or the alias. It should be the same controller, and you should be using GET, so I believe you need to go with the path parameter or query parameter.
This choice is independent of query rewriting, by the way.

Codeigniter routing URL with product name to product id

I need to redirect the URLs like this http://mysite.com/store/store-name to http://mysite.com/stores/products/store-id. Note that i need to get the store id from the database. So is it possible to do db operations in routes.php?
And in documentation the syntax is give as $route['store/:any']. How to get the value of second parameter here which is mentioned as :any.
There's not really any good nor simple way of running database queries through the routes. You can however have in the beginning of the controller function a validation.
I asume your store-name is some sort of slug for the product? Basicly you can validate if value is numeric or not, and if not find by slug and then redirect.
config/routes.php
$route["store/(.*)"] = 'stores/products/$1';
/* () and $1 together passes the values */
controllers/stores.php
/* Class etc. */
function products($mix) {
if (is_numeric($mix))
$int_id = $mix;
else {
$row = $this->get_where('products', array('slug' => $mix))->row();
$this->load->helper('url');
redirect("stores/products/{$row->id}");
}
/* Do stuff with the $int_id */
}
This asumes that you have:
A table named products
A column named id that's your products id
A column named slug that that's based on your store-name
I may be a little late to the party, but I may have an alternative suggestion.
I use the following for my routes:
http://mysite.com/store/1/store-name
Reason being... Based on your method, if you create
http://mysite.com/store/store-name
but then after a period of time (of which no doubt Google has indexed your page) you decide for what ever reason you have to change the name of the store to "Wonderful store name", you would naturally change your link to
http://mysite.com/store/wonderful-store-name
Which kills your SEO and any index links.
My solution of using http://mysite.com/store/1/store-name means that you can change store-name to anything you want, but it will always reference 1 meaning the user will still see the related page.
Anything is possible with CodeIgniter routes. Its all in the way you code it. Routing in CI is really flexible. You can use regular expressions besides the standard CI wildcards (:any)(:num). You can even add prefixes or suffixes to the path variables if you have to like:
$route['store/(:any)'] = "redircontroller/redirfunction/$1";
// for instance the namelookup method of the mystores controller
$route['stores/products/(:any)'] = "mystores/namelookup/$1";
You get the second parameter(and third and so on) by defining the variables in your route value which get passed to the controller method you define. If 'products' in you new url is also a variant you should start your wildcard expression there instead. You could also pull parameters out of the url using the URI class ($this->uri->segment(n)).
You don't, however, do database operations in routes.php. You do your database operations in the controller where you route to. My guess is that you'll have to match the store id using whatever is used in the url in a query.
In any case the path that you are using the routes file for is the path the user will see. To do the redirect you have to accept the original path and then redirect the user to the new path like so:
// in some controller that's attached to the original url
public function redirfunct($var){
$this->load->helper('url');
redirect(base_url('stores/products/' . $var));
}
I hope this helps you.
Yes that is easy, you only need to show the ID instead of the name,
you must be doing like storeName> Click to view details
Make it as
storeId> Click to view details
and when you are passing the parameter to the database, change the check of mysql, change it to id instead of name , that can be some like
" select yourRequiredColumn from table_name where id=".parameter."
Thanks

Resources