Closed Eilon closed 6 years ago
Thanks for contacting us, @knyzorg. @rynowak, what are your thoughts regarding this?
@knyzorg - at a high level what are you trying to accomplish?
Really I just want to be able to have synonyms for controller and action names. I want /foo/bar
to trigger the same code paths as /oof/rab
if I so desire.
The reason for this is URL internationalization, I want to have urls look like en/hello/world
and fr/salut/monde
which map to the same page. I would leave MVC behind completely in favor of writing my own convention, but the convenience of having url templates and generating anchor tags automatically is too good to pass up.
Another need which I have, is for it not to break virtual paths (IIS).
Ideally, none of the synonyms would be hard-coded, I would rather be able to have some logic deciding what action (if any) the requested one is synonymous to during a request.
Anything like this possible?
Thanks, that's what I thought you might be asking 😀
to trigger the same code paths as /oof/rab if I so desire
Should this include views? If you have views, will this include different .cshtml
files for each locale?
How do you want/expect link generation to work? Do you want something like:
Url.Action("World", "Hello", new { locale = "fr" }) -> /fr/salut/monde
OR
Url.Action("Monde", "Salut") -> /fre/salut/monde
I'm asking for clarification because there are a few difference schemes for how to implement something like this. The major pivot is whether you want to introduce another route value that represents the locale, or whether you want to localize the route values themselves.
If the link generation could work by allowing me to specify the local myself, that would really be ideal if possible. So the first variant please.
Url.Action
is basically the same thing as the <a>
helper tag, right?
Url.Action is basically the same thing as the helper tag, right?
Yes, exactly.
Give me a bit, I'll whip up a sample of this.
@knyzorg - reading through your question again, I'm wondering if I forgot to point out something obvious.
You can change routes.DefaultHandler
so that it points to your custom route. Then you'll be called with the route values on the way in, and when links are being generated.
Inside RouteAsync
translate the values from the locale to whatever language you're writing code in, and then do the reverse in GetVirtualPath
routes.DefaultHandler = new TranslationRoute(routes.DefaultHandler);
Is this what you're looking for?
Another option that I've helped people used in the past is to use IActionModelConvention
to 'multiply' actions - you can do all of the translations at startup time, and we'll handle all of the processing for you.
This won't be useful to you if you need to loop up the strings when each request is processed. Let me know if you're interested in this instead and I'll put together a sample.
How would TranslationRoute
be implemented?
Inside RouteAsync translate the values from the locale to whatever language you're writing code in, and then do the reverse in GetVirtualPath
It's really going over my head. I don't know to implement a route by myself. I thought of extending the Route class to make a TranslationRoute but Route wants a third parameter in the constructor involving inline constraints which I never even heard of before.
This is my first project in .NET and I may need some hand holding.
OK thanks for the feedback, I'll get back to you in a bit with a more fleshed out sample.
Here's a sample: https://github.com/aspnet/Mvc/compare/rynowak/localization-routing?expand=1
There's a few things that are slightly non-obvious and clunky.
Creating the routes themselves is kinda gross because there are so many parameters that are rarely used https://github.com/aspnet/Mvc/compare/rynowak/localization-routing?expand=1#diff-cd035ee26336357cbade86282aad4a22R73
If you're using default values in the routes, you have 'translate' them in the defaults as well. https://github.com/aspnet/Mvc/compare/rynowak/localization-routing?expand=1#diff-cd035ee26336357cbade86282aad4a22R87
In the route, when you're doing link generation (GetVirtualPath
) you will need to copy the 'language' from ambient values to values, in order for the correct route to be selected. https://github.com/aspnet/Mvc/compare/rynowak/localization-routing?expand=1#diff-42421a02d0010b370b9d53f0cee75762R31
If you're planning on using other localization features in ASP.NET Core then it would probably help to read over: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/localization?view=aspnetcore-2.1
In particular if you're using other MVC localization features then you will probably want to write an IResourceFilter
that sets the current culture based on the language
route value.
It seems to be essentially what I was looking for. Thanks. I will try it out as soon as I can and will get back to you.
Great, I'm going to close this. Feel free to open another issue if you need something else.
Hey @rynowak, I plugged it in and it seems to be working. I also managed to understand why it works which is great.
However, why are you repeating the creation of routes while a single route seems to be working fine:
app.UseMvc(routes =>
{
routes.Routes.Add(new TranslationRoute(
translations,
routes.DefaultHandler,
routeName: null,
routeTemplate: "{language=en}/{controller=Home}/{action=Index}/{id?}",
defaults: new RouteValueDictionary(new { }),
constraints: null,
dataTokens: null,
inlineConstraintResolver: routes.ServiceProvider.GetRequiredService<IInlineConstraintResolver>()));
});
(Moved defaults language to the route template)
This would also work fine. My example (multiple routes) limits the number of languages that can match. In your example it would match any string with that first segment: /foobar/Home/Index
and bind it to the language route value.
From @knyzorg on Monday, 13 August 2018 20:01:26
I am working on an .NET Core MVC application which requires alternative controller/action names to be allowed. To accomplish this, I am using my own Router on a MapRoute:
My custom router observes the requested controller and action, and based on it places a new value into the RouteData in the request:
However, to determine the value of the requestedAction, I am basically taking the requested path, splitting it and getting the value of it that way. This seems suboptimal.
What I would like to do would look something like this:
Another solution to this problem which I would very much enjoy is if I could do the following:
But NOT have my something route actually route anything and only serve as a way to define the RouteData for my CustomRouter.
Is either of these possible? I do not like the idea us uncleanly implementing existing functionality as it is a both a code smell and a potential maintenance difficulty in the future.
Copied from original issue: aspnet/Home#3427