How can I properly localize Razor Views in ServiceStack - razor

I am currently getting the prefered Culture from the Accept-Language-HTTP-Header and storing it in the AuthUserSession.
In AppHost.Configure:
PreRequestFilters.Add((httpReq, httpResp) =>
{
var session = httpReq.GetSession();
if (session is AuthUserSession)
{
var auths = ((AuthUserSession)session);
if (auths.Culture == null)
{
//parse languages
var languages = httpReq.Headers["Accept-Language"];
//auths.Culture = Helpers.CultureHelper.GetBestAcceptLanguageMatch(languages);
auths.Culture = "en-US";
httpReq.SaveSession(session, new TimeSpan(0, 20, 0));
}
}
});
My current solution to Render a View in the users prefered Culture is to change the current Threads UICulture from the Razor view:
#inherits ViewPage<LandingPage.ServiceModel.Operations.AskQuestions>
#{
var session = GetSession<ServiceStack.ServiceInterface.Auth.AuthUserSession>();
var prevCulture = System.Threading.Thread.CurrentThread.CurrentUICulture;
System.Threading.Thread.CurrentThread.CurrentUICulture = System.Globalization.CultureInfo.GetCultureInfo(session.Culture);
//access a Resource
ViewBag.Title = Resources.AskTitle;
}
Views Content
#{
System.Threading.Thread.CurrentThread.CurrentUICulture = prevCulture;
}
This seems unelegant and clumsy. What would be a better way to do this?
*edit:
I am looking for two hook points: one just before the View gets called, and one right after it got rendered. These should keep the interference with other Requests that get served to zero.

I discovered today that a custom IServiceRunner supplies just the right hooks (see https://github.com/ServiceStack/ServiceStack/wiki/Customize-HTTP-Responses).
As the one above it only works, when the page is served by a Service, because the RequestFilters and the ServiceRunner are not even touched when a ContentPage is requested.
It might be of interest, that the RequestFilter is another hook point, that is called before the Execution of the View. But the same seems true for the ResponseFilter. A small test in which I tried to reset the CurrentUICulture in the ResponseFilter rendered my page unlocalized.
In AppHost
public override void Configure(Funq.Container container)
{
//plugins
Plugins.Add(new RazorFormat());
Plugins.Add(new AuthFeature(() =>
new AuthUserSession(),
new IAuthProvider[] {
new BasicAuthProvider()
}));
//request filters
PreRequestFilters.Add((httpReq, httpResp) =>
{
var session = httpReq.GetSession();
if (session is AuthUserSession)
{
var auths = ((AuthUserSession)session);
if (auths.Culture == null)
{
var languages = httpReq.Headers["Accept-Language"];
auths.Culture = Helpers.CultureHelper.GetBestAcceptLanguageMatch(languages);
httpReq.SaveSession(session, new TimeSpan(0, 20, 0));
}
httpReq.SetItem("Culture", auths.Culture);
}
});
//funq
var userRep = new InMemoryAuthRepository();
container.Register<IUserAuthRepository>(userRep);
container.Register<ICacheClient>(c => new MemoryCacheClient());
}
//use a custom IServiceRunner
public override ServiceStack.ServiceHost.IServiceRunner<TRequest> CreateServiceRunner<TRequest>(ActionContext actionContext)
{
var runner = base.CreateServiceRunner<TRequest>(actionContext);
return new CultureAwareServiceRunner<TRequest>(this, actionContext);
}
CultureAwareServiceRunner.cs
public class CultureAwareServiceRunner<T> : ServiceRunner<T>
{
public CultureAwareServiceRunner(AppHost appHost, ServiceStack.WebHost.Endpoints.ActionContext actionContext) :
base(appHost, actionContext)
{ }
public override void OnBeforeExecute(IRequestContext requestContext, T request)
{
var httpReq = requestContext.Get<IHttpRequest>();
httpReq.SetItem("PreviousCulture", Thread.CurrentThread.CurrentUICulture);
string culture = httpReq.GetItem("Culture") as string;
if (culture != null)
Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo(culture);
base.OnBeforeExecute(requestContext, request);
}
public override object OnAfterExecute(IRequestContext requestContext, object response)
{
var httpReq = requestContext.Get<IHttpRequest>();
var prevCulture = httpReq.GetItem("PreviousCultureCulture") as CultureInfo;
if (prevCulture != null)
Thread.CurrentThread.CurrentUICulture = prevCulture;
return base.OnAfterExecute(requestContext, response);
}
}

Related

SignalR + Win RT(Windows 8.1) + using unsigned certificate not working [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
After searching for more than 4 hours, making a Win RT + SignalR work with a selfsigned certificate. Found it! So I share a solution here.
You get the error:
The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel.
The remote certificate is invalid according to the validation procedure.
public class DefaultHttpClientUnsigned : DefaultHttpClient
{
protected override HttpMessageHandler CreateHandler()
{
var filter = new HttpBaseProtocolFilter();
filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.Expired);
filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.Untrusted);
filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.InvalidName);
filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.IncompleteChain);
var handler = new WinRtHttpClientHandler(filter);
return handler;
}
}
Then for creating the connection:
var connection = new HubConnection(address);
var client = new DefaultHttpClientUnsigned();
connection.Start(client);
// https://www.nuget.org/packages/WinRtHttpClientHandler
The source code for the WinRtHttpClientHandler (if it's not available anymore)
public class WinRtHttpClientHandler : HttpMessageHandler
{
private static readonly Version NoVersion = new Version(0, 0);
private static readonly Version Version10 = new Version(1, 0);
private static readonly Version Version11 = new Version(1, 1);
private readonly rt.HttpClient _client;
private bool _disposed = false;
public WinRtHttpClientHandler(IHttpFilter httpFilter)
{
_client = new rt.HttpClient(httpFilter);
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
CheckDisposed();
var rtMessage = await ConvertHttpRequestMessaageToRt(request, cancellationToken).ConfigureAwait(false);
var resp = await _client.SendRequestAsync(rtMessage).AsTask(cancellationToken).ConfigureAwait(false);
var netResp = await ConvertRtResponseMessageToNet(resp, cancellationToken).ConfigureAwait(false);
return netResp;
}
internal static async Task<rt.HttpRequestMessage> ConvertHttpRequestMessaageToRt(HttpRequestMessage message, CancellationToken token)
{
var rt = new rt.HttpRequestMessage()
{
Method = new rt.HttpMethod(message.Method.Method),
Content = await GetContentFromNet(message.Content).ConfigureAwait(false),
RequestUri = message.RequestUri,
};
CopyHeaders(message.Headers, rt.Headers);
foreach (var prop in message.Properties)
rt.Properties.Add(prop);
return rt;
}
internal static async Task<HttpRequestMessage> ConvertRtRequestMessageToNet(rt.HttpRequestMessage message, CancellationToken token)
{
var req = new HttpRequestMessage()
{
Method = new HttpMethod(message.Method.Method),
RequestUri = message.RequestUri,
Content = await GetNetContentFromRt(message.Content, token).ConfigureAwait(false),
};
foreach (var header in message.Headers)
req.Headers.TryAddWithoutValidation(header.Key, header.Value);
foreach (var prop in message.Properties)
req.Properties.Add(prop);
return req;
}
internal static void CopyHeaders(IEnumerable<KeyValuePair<string, IEnumerable<string>>> source, IDictionary<string, string> destination)
{
var headers = from kvp in source
from val in kvp.Value
select new KeyValuePair<string, string>(kvp.Key, val);
foreach (var header in headers)
destination.Add(header);
}
internal static async Task<rt.IHttpContent> GetContentFromNet(HttpContent content)
{
if (content == null)
return null;
var stream = await content.ReadAsStreamAsync().ConfigureAwait(false);
var c = new rt.HttpStreamContent(stream.AsInputStream());
CopyHeaders(content.Headers, c.Headers);
return c;
}
internal static async Task<HttpContent> GetNetContentFromRt(rt.IHttpContent content, CancellationToken token)
{
if (content == null)
return null;
var str = await content.ReadAsInputStreamAsync().AsTask(token).ConfigureAwait(false);
var c = new StreamContent(str.AsStreamForRead());
foreach (var header in content.Headers)
c.Headers.TryAddWithoutValidation(header.Key, header.Value);
return c;
}
internal static async Task<HttpResponseMessage> ConvertRtResponseMessageToNet(rt.HttpResponseMessage message, CancellationToken token)
{
var resp = new HttpResponseMessage((HttpStatusCode)(int)message.StatusCode)
{
ReasonPhrase = message.ReasonPhrase,
RequestMessage = await ConvertRtRequestMessageToNet(message.RequestMessage, token).ConfigureAwait(false),
Content = await GetNetContentFromRt(message.Content, token).ConfigureAwait(false),
Version = GetVersionFromEnum(message.Version),
};
foreach (var header in message.Headers)
resp.Headers.TryAddWithoutValidation(header.Key, header.Value);
return resp;
}
internal static Version GetVersionFromEnum(rt.HttpVersion version)
{
switch (version)
{
case rt.HttpVersion.None:
return NoVersion;
break;
case rt.HttpVersion.Http10:
return Version10;
break;
case rt.HttpVersion.Http11:
return Version11;
break;
default:
throw new ArgumentOutOfRangeException("version");
}
}
private void CheckDisposed()
{
if (_disposed)
throw new ObjectDisposedException("WinRtHttpClientHandler");
}
protected override void Dispose(bool disposing)
{
if (disposing && !_disposed)
{
_client.Dispose();
_disposed = true;
}
base.Dispose(disposing);
}
}
Hope this helps some people out there.

BackgroundTask in Lifecycle Events works but not automatically

I am trying to update the data in my secondary tile using a background task. It gets updated when I select my background task from the lifecycle events dropdown. However it doesn't work automatically. Does it mean that my SystemTrigger is not getting fired? Please help.
Here is my code:
public static void CheckIfBackgroundTaskExist()
{
if (BackgroundTaskRegistration.AllTasks.Count < 1)
{
RegisterBackgroundTask();
}
}
public static void RegisterBackgroundTask()
{
BackgroundTaskBuilder builder = new BackgroundTaskBuilder();
builder.Name = "SecondaryTileUpdate";
builder.TaskEntryPoint = "BackgroundTaskLiveTile.SecondaryTileUpdater";
//IBackgroundTrigger trigger = new MaintenanceTrigger(15, false);
IBackgroundTrigger trigger = new SystemTrigger(SystemTriggerType.TimeZoneChange, false);
builder.SetTrigger(trigger);
IBackgroundTaskRegistration task = builder.Register();
}
public async void Run(IBackgroundTaskInstance taskInstance)
{
//HERE: request a deferral
var deferral = taskInstance.GetDeferral();
var list = await SecondaryTile.FindAllAsync();
foreach (SecondaryTile liveTile in list)
{
HttpClient client = new HttpClient();
var response = await client.GetAsync(url, HttpCompletionOption.ResponseContentRead);
if (!response.IsSuccessStatusCode)
{
//
}
if (response != null)
{
string content = await response.Content.ReadAsStringAsync();
try
{
MyProperty= JsonConvert.DeserializeObject<MyClass>(content);
}
catch
{
//MessageBox.Show("Unable to retrieve data");
}
}
// Update Secondary Tiles
if (liveTile.TileId == "MySecondaryTileId")
{
await UpdateMyTile();
}
}
}

Removing First Item from listbox while binding to listbox

I have parsed the feed http://www.toucheradio.com/toneradio/android/toriLite/AndroidRSS.xml
And all items from rss feed displayed in listbox.Now I dont want to get first item I have to omit it.How Can I do it.
MainPage.xaml.cs:
namespace tori
{
public partial class MainPage : PhoneApplicationPage
{
// Constructor
public MainPage()
{
InitializeComponent();
// is there network connection available
if (!System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable())
{
MessageBox.Show("No network connection available!");
return;
}
// start loading XML-data
WebClient downloader = new WebClient();
Uri uri = new Uri(" http://www.toucheradio.com/toneradio/android/toriLite/AndroidRSS.xml", UriKind.Absolute);
downloader.DownloadStringCompleted += new DownloadStringCompletedEventHandler(ChannelDownloaded);
downloader.DownloadStringAsync(uri);
}
void ChannelDownloaded(object sender, DownloadStringCompletedEventArgs e)
{
if (e.Result == null || e.Error != null)
{
MessageBox.Show("There was an error downloading the XML-file!");
}
else
{
// Deserialize if download succeeds
XDocument document = XDocument.Parse(e.Result);
var queue = from item in document.Descendants("item")
select new Item
{
title = item.Element("title").Value
,
link = item.Element("link").Value
,
ThumbnailUrl = item.Element(item.GetNamespaceOfPrefix("media") + "thumbnail").Attribute("url").Value
,
};
itemsList.ItemsSource = queue;
}
}
public class Item
{
public string title { get; set; }
public string ThumbnailUrl { get; set; }
public string link { get; set; }
}
If I write queue.RemoveAt(0);
i was getting error at RemoveAt.
Can anybody please tell me how can I do that.
Many Thanks in advance.
You can easily do this using LINQ Skip extension method (documentation here).
Just try the sample below:
itemsList.ItemsSource = queue.Skip(1);
As well you can rewrite the query to omit the first item before applying the projection in the select method using the methods chain approach:
var queue = document.Descendants("item")
.Skip(1)
.Select(item => new Item
{
title = item.Element("title").Value,
link = item.Element("link").Value,
ThumbnailUrl = item.Element(item.GetNamespaceOfPrefix("media") + "thumbnail").Attribute("url").Value,
})
.ToList();
itemsList.ItemsSource = queue;
UPDATE / DUE TO COMMENTS
And as well if you need to skip items at certain indexes you may use the Where method and the HasSet as in the sample below:
var document = XDocument.Parse(e.Result);
var indexes = new HashSet<int> { 1, 3, 4 };
var queue = document.Descendants("item")
.Select(item => new Item
{
title = item.Element("title").Value,
link = item.Element("link").Value,
ThumbnailUrl =
item.Element(item.GetNamespaceOfPrefix("media") + "thumbnail").Attribute("url").Value,
})
.Where((x, i) => !indexes.Contains(i))
.ToList();
Items.ItemsSource = queue;

How cancel Async Call in Windows Phone?

I have a list wich is loaded with elements each time the user make a research...These elements contain an Icon which is dowloaded with an async method GetByteArrayAsync of the HttpClient object. I have an issue when the user make a second research while the icon of the first list are still downloading.Because the list of elements is changing while Icon downloads are processing on each element of the first list. So my guess is that I need to cancel these requests each time the user proceed to a new research...Ive readen some stuuf on Task.run and CancellationTokenSource but I can't find really helpful example for my case so here is my code...Hope you can help me with that ...Thank you
public static async Task<byte[]> DownloadElementFile(BdeskElement bdeskElement)
{
//create and send the request
DataRequest requesteur = new DataRequest();
byte[] encryptedByte = await requesteur.GetBytesAsync(dataRequestParam);
return encryptedByte;
}
public async Task<Byte[]> GetBytesAsync(DataRequestParam datarequesparam)
{
var handler = new HttpClientHandler { Credentials = new NetworkCredential(datarequesparam.AuthentificationLogin, datarequesparam.AuthentificationPassword, "bt0d0000") };
HttpClient httpClient = new HttpClient(handler);
try
{
byte[] BytesReceived = await httpClient.GetByteArrayAsync(datarequesparam.TargetUri);
if (BytesReceived.Length > 0)
{
return BytesReceived;
}
else
{
return null;
}
}
catch (WebException)
{
throw new MyException(MyExceptionsMessages.Webexception);
}
}
EDIT
public async Task<Byte[]> GetBytesAsync(DataRequestParam datarequesparam)
{
var handler = new HttpClientHandler { Credentials = new NetworkCredential(datarequesparam.AuthentificationLogin, datarequesparam.AuthentificationPassword, "bt0d0000") };
HttpClient httpClient = new HttpClient(handler);
try
{
cts = new CancellationTokenSource();
HttpResponseMessage reponse = await httpClient.GetAsync(datarequesparam.TargetUri,cts.Token);
if (reponse.StatusCode == HttpStatusCode.OK)
{
byte[] BytesReceived = reponse.Content.ReadAsByteArrayAsync().Result;
if (BytesReceived.Length > 0)
{
return BytesReceived;
}
else
{
return null;
}
}
else
{
return null;
}
}
catch (WebException)
{
throw new MyException(MyExceptionsMessages.Webexception);
}
catch(OperationCanceledException)
{
throw new OperationCanceledException();
}
EDIT2
I need to cancel this funntion when the user make a new research and the list "listBoxGetDocsLibs" changed.
private async void LoadIconDocLibs()
{
foreach (var doclib in listBoxGetDocsLibs)//ERROR HERE COLLECTION HAS CHANGED
{
doclib.Icon = new BitmapImage();
try
{
byte[] Icon = await ServerFunctions.GetDocLibsIcon(doclib);
if (Icon != null)
{
{
var ms = new MemoryStream(Icon);
BitmapImage photo = new BitmapImage();
photo.DecodePixelHeight = 64;
photo.DecodePixelWidth = 92;
photo.SetSource(ms);
doclib.Icon = photo;
}
}
}
catch(OperationCanceledException)
{
}
}
}
First you need to define CancellationTokenSource:
private System.Threading.CancellationTokenSource cts;
place above code somewhere, where you can access it with your Button or other method.
Unfortunately GetByteArrayAsync lacks Cancelling - so it cannot be used with cts.Token, but maybe you can accomplish your task using GetAsync - which supports Cancelling:
ctsDownload = new System.Threading.CancellationTokenSource();
HttpResponseMessage response = await httpClient.GetAsync(requestUri, cts.Token);
Then you can get your content from response.
And when you want to Cancel your Task it can look like this:
private void cancelBtn_Click(object sender, RoutedEventArgs e)
{
if (this.cts != null)
this.cts.Cancel();
}
When you Cancel task an Exception will be thrown.
If you want to cancel your own async Task, a good example you can find at Stephen Cleary blog.
EDIT - you can also build your own method (for example with HttpWebRequest) which will support Cancelling:
For this purpose you will have to extend HttpWebRequest (under WP it lacks GetResponseAsync):
// create a static class in your namespace
public static class Extensions
{
public static Task<HttpWebResponse> GetResponseAsync(this HttpWebRequest webRequest)
{
TaskCompletionSource<HttpWebResponse> taskComplete = new TaskCompletionSource<HttpWebResponse>();
webRequest.BeginGetResponse(
asyncResponse =>
{
try
{
HttpWebRequest responseRequest = (HttpWebRequest)asyncResponse.AsyncState;
HttpWebResponse someResponse = (HttpWebResponse)responseRequest.EndGetResponse(asyncResponse);
taskComplete.TrySetResult(someResponse);
}
catch (WebException webExc)
{
HttpWebResponse failedResponse = (HttpWebResponse)webExc.Response;
taskComplete.TrySetResult(failedResponse);
}
catch (Exception exc) { taskComplete.SetException(exc); }
}, webRequest);
return taskComplete.Task;
}
}
Then your method can look like this:
public async Task<Byte[]> GetBytesAsync(DataRequestParam datarequesparam, CancellationToken ct)
{
HttpWebRequest request = HttpWebRequest.CreateHttp(datarequesparam.TargetUri);
request.Method = "GET";
request.Credentials = new NetworkCredential(datarequesparam.AuthentificationLogin, datarequesparam.AuthentificationPassword, "bt0d0000");
request.AllowReadStreamBuffering = false;
try
{
if (request != null)
{
using (HttpWebResponse response = await request.GetResponseAsync())
using (Stream mystr = response.GetResponseStream())
using (MemoryStream output = new MemoryStream())
{
const int BUFFER_SIZE = 10 * 1024;
byte[] buf = new byte[BUFFER_SIZE];
int bytesread = 0;
while ((bytesread = await mystr.ReadAsync(buf, 0, BUFFER_SIZE)) > 0)
{
output.Write(buf, 0, bytesread);
ct.ThrowIfCancellationRequested();
}
return output.ToArray();
}
}
else return null;
}
catch (WebException)
{
throw new MyException(MyExceptionsMessages.Webexception);
}
}
You can freely change Buffer Size which will affect how often Cancellation will be checked.
I haven't tried this but I think it should work.

Localized ViewEngines using multiple routes

I am trying to make a simple multi-language website. Overriding FindView to get the file based on the language is easy, my problem comes in the routing part.
I would like to do is: (have a website with 2 languages - pt-br and en-us, let abbreviate to onlu pt and en - the default would be PT)
User types www.mysite.com -> would find the languages in the user header request and if the user doesn´t have any of them, he would be redirected to the default PT, so the end result would be www.mysite.com in Portuguese. If he has en, he would be redirected to www.mysite.com/en/ , the result would be the view in English.
If the user types www.mysite.com/pt/ -> I would check that he wants the default and would redirect to www.mysite.com in Portuguese.
I did a custom engine to get the correct view based on the language. But it´s not working 100% because the routing problem.
IN my case I am trying to route with
routes.MapRoute(
"Localization", // Route name
"{lang}/{controller}/{action}", // URL with parameters
new { lang = "pt", controller = "Home", action = "Index" } //defaults
);
But with this, when someone types /pt/ will not redirect to the root of the site.
Another problem with the route is that I don´t want to anyone typing the controller name, I just want the action, my website just have one Home controller with few actions.
Another problem is the that I want a different action name, like, CONTACT in English and CONTATO in Portuguese, they should appear on the address bar like www.mysite.com/Contato or www.mysite.com/en/Contact
Mu Engine I did base on this solution http://www.counity.at/blog/2012/asp-net-mvc3-localization-using-culture-dependent-views/ by Guido Breitenhuber
Here is the code with some tweaks (it´s not working 100% yet)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Globalization;
namespace Ala.MultiLanguage
{
public class LocalizedViewLocation : RazorViewEngine
{
private static readonly string[] _emptyLocations = new string[0];
public string[] LocalizedViewLocationFormats { get; set; }
public string[] LocalizedMasterLocationFormats { get; set; }
protected string[] LocalizedPartialViewLocationFormats { get; set; }
public LocalizedViewLocation()
{
// Define the localized view locations
// 0: Language
// 1: View name
// 2: Controller name
LocalizedViewLocationFormats = new[] {
"~/Views/{0}/{2}/{1}.cshtml",
"~/Views/Shared/{0}/{1}.cshtml"};
MasterLocationFormats = new[] {
"~/Views/{0}/{2}/{1}.cshtml",
"~/Views/Shared/{0}/{1}.cshtml"};
LocalizedPartialViewLocationFormats = new[] {
"~/Views/{0}/{2}/{1}.cshtml",
"~/Views/Shared/{0}/{1}.cshtml"};
}
public override ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache)
{
if (controllerContext == null)
throw new ArgumentNullException("controllerContext");
if (String.IsNullOrEmpty(partialViewName))
throw new ArgumentException("Parameter partialViewName is null or empty.", "partialViewName");
string[] searched;
var controllerName = controllerContext.RouteData.GetRequiredString("controller");
var partialPath = GetPath(controllerContext, LocalizedPartialViewLocationFormats, partialViewName, controllerName, out searched);
if (String.IsNullOrEmpty(partialPath))
{
var baseRes = base.FindPartialView(controllerContext, partialViewName, useCache);
if (baseRes.View != null)
return baseRes;
return new ViewEngineResult(searched.Union(baseRes.SearchedLocations));
}
return new ViewEngineResult(CreatePartialView(controllerContext, partialPath), this);
}
public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
{
if (controllerContext == null)
throw new ArgumentNullException("controllerContext");
if (String.IsNullOrEmpty(viewName))
throw new ArgumentException("Parameter viewName is null or empty.", "viewName");
string[] viewLocationsSearched;
string[] masterLocationsSearched;
var controllerName = controllerContext.RouteData.GetRequiredString("controller");
var viewPath = GetPath(controllerContext, LocalizedViewLocationFormats, viewName, controllerName, out viewLocationsSearched);
var masterPath = GetPath(controllerContext, LocalizedMasterLocationFormats, masterName, controllerName, out masterLocationsSearched);
if (String.IsNullOrEmpty(viewPath) || (String.IsNullOrEmpty(masterPath) && !String.IsNullOrEmpty(masterName)))
{
var baseRes = base.FindView(controllerContext, viewName, masterName, useCache);
if (baseRes.View != null)
return baseRes;
return new ViewEngineResult(viewLocationsSearched.Union(masterLocationsSearched).Union(baseRes.SearchedLocations));
}
return new ViewEngineResult(CreateView(controllerContext, viewPath, masterPath), this);
}
private string GetPath(ControllerContext controllerContext, string[] locations, string name, string controllerName, out string[] searchedLocations)
{
searchedLocations = _emptyLocations;
if (String.IsNullOrEmpty(name))
return String.Empty;
if (IsSpecificPath(name))
return String.Empty;
return GetPathFromGeneralName(controllerContext, locations, name, controllerName, ref searchedLocations);
}
private static bool IsSpecificPath(string name)
{
char c = name[0];
return (c == '~' || c == '/');
}
private string GetPathFromGeneralName(ControllerContext controllerContext, string[] locations, string name, string controllerName, ref string[] searchedLocations)
{
var result = String.Empty;
searchedLocations = new string[locations.Length];
for (int i = 0; i < locations.Length; i++)
{
var location = locations[i];
var virtualPath = string.Format(CultureInfo.InvariantCulture, location, CultureInfo.CurrentUICulture.TwoLetterISOLanguageName, name, controllerName);
if (FileExists(controllerContext, virtualPath))
{
searchedLocations = _emptyLocations;
result = virtualPath;
break;
}
searchedLocations[i] = virtualPath;
}
return result;
}
}
}
Well, after some timing trying to do in the best way, I ´ve found one solution much easier and fast to implement.
Just mapped the routes that I want one-by-one in the global.asax. This will work and will be fast to implement if you have only few pages and languages.
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute("Default-BR", "", new { controller = "Home", action = "Index" });
routes.MapRoute("Default-EN", "en", new { controller = "Home", action = "IndexEN" });
routes.MapRoute("HotelBR", "Hotel", new { controller = "Home", action = "Index" });
routes.MapRoute("HotelEN", "en/Hotel", new { controller = "Home", action = "IndexEN" });
routes.MapRoute("Apartamento", "Apartamento", new { controller = "Home", action = "Apartamentos" });
routes.MapRoute("Apartamentos", "Apartamentos", new { controller = "Home", action = "Apartamentos" });
routes.MapRoute("Apartments", "en/Apartments", new { controller = "Home", action = "ApartamentosEN" });
routes.MapRoute("Localizacao", "Localizacao", new { controller = "Home", action = "Localizacao" });
routes.MapRoute("Location", "en/Location", new { controller = "Home", action = "LocalizacaoEN" });
routes.MapRoute("Tarifa", "Tarifa", new { controller = "Home", action = "Tarifas" });
routes.MapRoute("Tarifas", "Tarifas", new { controller = "Home", action = "Tarifas" });
routes.MapRoute("Rates", "en/Rates", new { controller = "Home", action = "TarifasEN" });
routes.MapRoute("Reserva", "Reserva", new { controller = "Home", action = "Reservas" });
routes.MapRoute("Reservas", "Reservas", new { controller = "Home", action = "Reservas" });
routes.MapRoute("Booking", "en/Booking", new { controller = "Home", action = "ReservasEN" });
routes.MapRoute("Contato", "Contato", new { controller = "Home", action = "Contato" });
routes.MapRoute("Contact", "en/Contact", new { controller = "Home", action = "ContatoEN" });