Override mobile detection method in ASP.NET MVC 5? - mobile

I like the simplicity of the ASP.NET MVC 5 mobile detection feature which allows you to just add a view with .mobile extension to automatically serve that mobile view to mobile browsers. However, I would like to use a different mobile detection script: http://detectmobilebrowser.com/mobile, rather than the built-in detection script.
I could add code to the controller like:
if (isMobile()) {
return View("IndexMobile"); }
else {
return View(); }
However, I would prefer not to add custom If-Then logic do the Controller if there is a way to use the built-in .mobile extension feature while overriding the method of detecting mobile browsers.
Is there a way to use a custom mobile detection script with the built-in MVC 5 feature for routing to the view with .mobile extension?

For using code from http://detectmobilebrowser.com/mobile do this:
create method for detecting mobile device:
public string IsMobileDevice(string ua)
{
Regex b = new Regex(#"(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino", RegexOptions.IgnoreCase | RegexOptions.Multiline);
Regex v = new Regex(#"1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-", RegexOptions.IgnoreCase | RegexOptions.Multiline);
if ((b.IsMatch(ua) || v.IsMatch(ua.Substring(0, 4)))) {
return true;
}
return false;
}
then in Global.asax file in Application_Start method:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
.
.
.
DisplayModeProvider.Instance.Modes.Insert(0, new DefaultDisplayMode("mobile")
{
ContextCondition = (context => IsMobileDevice(context.GetOverriddenUserAgent())
});
}
Then add view with mobile extension like Index.mobile.cshtml
And in controller for detecting mobile:
public ActionResult Index()
{
if(IsMobileDevice(Request.ServerVariables["HTTP_USER_AGENT"])) {
// Logic for mobile request
}
return View();
}

Related

Blazor Wasm setting end user defined startpage

In my application I have many areas for different kinds of users. Controlled by roles.
So I would like to give the user an option to set a preferred startpage.
Deep Linking works, so no problems there.
My first attempt was this
#code{
[Parameter] public string Action { get; set; }
[Inject] private NavigationManager Navigation { get; set; }
private void LoginSucceeded(RemoteAuthenticationState state)
{
Console.WriteLine("navigate to DepartmentAccess");
// This works with on extra login
Navigation.NavigateTo("/DepartmentAccess", true);
// This loads 3 or more times
// state.ReturnUrl = "/DepartmentAccess";
}
}
Then I tried altering the return url in RedirectToLogin.razor. Here I added “MyStartPage”
#inject NavigationManager Navigation
#using Microsoft.AspNetCore.Components.WebAssembly.Authentication
#using Zeus.Client.PortfolioRights
#code {
protected override void OnInitialized()
{
Navigation.NavigateTo($"authentication/login?returnUrl={Uri.EscapeDataString(Navigation.Uri)/MyStartPage}");
}
}
This has absolutely no effekt!
Okay time to dig a little deeper
It’s the RemoteAuthenticatorViewCore that holds all the code related to the login process.
This function handles the Login state. It’s called after the redirect from Azure AD
private async Task ProcessLogIn(string returnUrl)
{
AuthenticationState.ReturnUrl = returnUrl;
var result = await AuthenticationService.SignInAsync(new RemoteAuthenticationContext<TAuthenticationState>
{
State = AuthenticationState
});
switch (result.Status)
{
case RemoteAuthenticationStatus.Redirect:
break;
case RemoteAuthenticationStatus.Success:
await OnLogInSucceeded.InvokeAsync(result.State);
await NavigateToReturnUrl(GetReturnUrl(result.State, returnUrl));
break;
case RemoteAuthenticationStatus.Failure:
_message = result.ErrorMessage;
Navigation.NavigateTo(ApplicationPaths.LogInFailedPath);
break;
case RemoteAuthenticationStatus.OperationCompleted:
default:
throw new InvalidOperationException($"Invalid authentication result status '{result.Status}'.");
}
}
The input parameter “returnUri” are set from this function
private string GetReturnUrl(TAuthenticationState state, string defaultReturnUrl = null)
{
if (state?.ReturnUrl != null)
{
return state.ReturnUrl;
}
var fromQuery = QueryStringHelper.GetParameter(new Uri(Navigation.Uri).Query, "returnUrl");
if (!string.IsNullOrWhiteSpace(fromQuery) && !fromQuery.StartsWith(Navigation.BaseUri))
{
// This is an extra check to prevent open redirects.
throw new InvalidOperationException("Invalid return url. The return url needs to have the same origin as the current page.");
}
return fromQuery ?? defaultReturnUrl ?? Navigation.BaseUri;
}
So I wonder. Why is the “defaultReturnUrl” not set when I alter the return uri?
Navigation.NavigateTo($"authentication/login?returnUrl={Uri.EscapeDataString(Navigation.Uri)/MyStartPage}
I guess that I don't understand the login flow. But got a feeling that I am close.
Just need to find a way to set the defaultReturnUrl
Please check if below points can be worked around.
The first step in getting a page (component) ready to participate in routing is to assign the component a route. You do that in the cshmtl file, using the page directive.
#page "/redirectpage" above #inject NavigationManager NavManager
Make sure to Add CascadingAuthenticationState and <AuthorizeView> in apps.razor and LoginDisplay component.It is responsible to display pages that the user is authorised to see.
(or)
If the page component for the route contains an authorize attribute (#attribute [Authorize]) then the user must be logged in, otherwise they will be redirected to the login page.
Example: if you wanted to secure the Counter.razor page just add an Authorize attribute to the top:
#using Microsoft.AspNetCore.Authorization
#attribute [Authorize]
Or
#attribute [Authorize(Roles = "finance")]
Add this to the pages that require authentication.
References:
Secure an ASP.NET Core Blazor WebAssembly standalone app with the
Authentication library | Microsoft Docs
Using Azure Active Directory to Secure Blazor WebAssembly Hosted
Apps (code-maze.com)
Secure an ASP.NET Core Blazor WebAssembly standalone app with Azure
Active Directory | Microsoft Docs

CefSharp: Injecting custom CSS File using a custom scheme

I'm using CefSharp (47) to render a webpage from a host that I have no control over, and I want to make some additional CSS tweaks to those provided by the host.
Reading up on various topics across GitHub (https://github.com/cefsharp/CefSharp/blob/cefsharp/47/CefSharp.Example/CefSharpSchemeHandlerFactory.cs), and here (CefSharp custom SchemeHandler), I wrote a custom scheme handler accordingly:
public class CustomSchemeHandlerFactory : ISchemeHandlerFactory
{
public const string SchemeName = "custom";
public IResourceHandler Create(IBrowser browser, IFrame frame, string schemeName, IRequest request)
{
Console.WriteLine(request.Url);
if (schemeName.ToLower() == SchemeName.ToLower())
{
// Do some stuff
}
return null;
}
}
I attempt to bind it in my application in the following manner:
CefSettings settings = new CefSettings();
settings.CachePath = browserCachePath;
settings.RegisterScheme(new CefCustomScheme()
{
SchemeName = CustomSchemeHandlerFactory.SchemeName,
SchemeHandlerFactory = new CustomSchemeHandlerFactory()
});
Cef.Initialize(settings);
The application then browses to the appropriate website, and uses the 'LoadingStateChanged' event to then fire off some JavaScript to inject the CSS file I want to load:
string linkText = "<link rel=\u0022stylesheet\u0022 type=\u0022text/css\u0022 href=\u0022custom://custom.css\u0022>";
var jsFunctionText = string.Format("(function() {{ $('head').append('{0}'); return true;}}) ();", linkText);
var injectionTask = await _myBrowser.GetMainFrame().EvaluateScriptAsync(jsFunctionText, null);
...which succeeds.
But my custom resource handler 'Create' event is never fired.
I can only presume that the handler isn't being registered properly, so I'd appreciate any advice/help in getting this working properly!
Thanks!

ServiceStack cant handle cookie from subdomain angular client

I have a problem on servicestack catch client cookie.
My Service domain : service.domain.com
Website (Angular) : www.domain.com
Each one on dedicated server.
I developing on Self-Host method in Servicestack 4.
Here is my Request Filter looks cookies than if noting than set thread culture.
this.PreRequestFilters.Add((httpReq, httpResp) =>
{
var lang = httpReq.GetCookieValue("Lang");
if (!string.IsNullOrEmpty(lang))
{
Thread.CurrentThread.CurrentUICulture = new CultureInfo(lang);
}
else
{
Thread.CurrentThread.CurrentUICulture = new CultureInfo("en");
httpResp.SetCookie("Lang","en",TimeSpan.FromDays(100));
}
});
and this is my Language service taking "Lang" parameter.
public class LanguageService : ServiceStack.Service
{
public Language Any(LanguageRequest request)
{
this.Response.SetCookie("Lang", request.Lang, TimeSpan.FromDays(100));
return new Language() { };
}
}
Unfortunalety prerequestfilter catch noting after languageservice.
Thanks for your suggestions.
By default Cookies in different sub domains are treated as separate domains.
You can try specifying the domain on each Cookie with:
SetConfig(new HostConfig {
RestrictAllCookiesToDomain = "domain.com",
});

How to Consume Secured Web Api from C# MVC and AngularJS

How to Consume Secured Web Api from other application C# MVC and AngularJS .
[Authorize(Users = "Steve,Mike")]
public class EmployeeController : ApiController
{
MyDB db = new MyDB();
public IEnumerable<EmployeeViewModel> GetAllEmployee()
{
return db.Employee.Select(item => new EmployeeViewModel { EmpID = item.EmpID, Name = item.Name, Region = item.Region }).ToList();
}
}
The following code I can get without Secure WebApi from AngularJS
var ft = searchText.toLowerCase();
$http.get('/api/Employee/GetAllEmployee').success(function (largeLoad) {
data = largeLoad.filter(function (item) {
return JSON.stringify(item).toLowerCase().indexOf(ft) != -1;
});
$scope.setPagingData(data, page, pageSize);
});
Your help is highly appreciated...
what kind of Secured Web Api do you want to consume?
you may think about oAuth

Unit testing with MVVM Light & DispatcherHelper

I have a SL4 app that utilizes the MVVM Light Toolkit. Within a view model, I call a data service that retrieves data from an OData service. Within the VM, I am using the DispatcherHelper utility class (part of MVVM Light) to update the property on the VM from the data in the callback I pass into the data service. For instance, my view model method looks like this:
public string CurrentUserLogin {
get {
if (string.IsNullOrEmpty(_currentUserLogin))
RetrieveCurrentUserLogin();
return string.IsNullOrEmpty(_currentUserLogin) ? _currentUserLogin : _currentUserLogin.Replace(#"\\", #"\");
}
set {
if (_currentUserLogin != value) {
_currentUserLogin = value;
RaisePropertyChanged(CurrentUserLoginPropertyName);
}
}
}
private void RetrieveCurrentUserLogin() {
DataService.GetCurrentUserLogin(result => {
DispatcherHelper.UIDispatcher.BeginInvoke(() => {
CurrentUserLogin = result;
});
});
}
And here's what my data service looks like:
public void GetCurrentUserLogin(Action<string> callback) {
// create query request
var query = OnDemandContext.CreateQuery<string>("GetCurrentUserLogin");
var request = (HttpWebRequest)WebRequest.Create(query.RequestUri);
request.BeginGetResponse(asyncResult => {
var responseStream = request.EndGetResponse(asyncResult).GetResponseStream();
var responseDocument = XDocument.Load(responseStream);
callback(responseDocument.Root.Value);
}, null);
}
Everything works great when I run my SL application. However the problem I have is when I try to write unit tests against it using the SL Unit Testing Framework. I can test my data service without an issue, but it seems the DispatcherHelper is throwing a wrench into all my tests as the DispatcherHelper.UIDispatcher is always null when fired. I'm assuming it has something to do with the initlization (which is in my SL app's Application_Startup()). I tried initializing it in my test app but that isn't helping. I've also tried using DispatcherHelper.CheckBeginInvokeOnUI() but that has no effect on the issue.
Ideas?
AC,
I just created a simple SL UT project and I did this in the App.XAML.CS
private void Application_Startup(object sender, StartupEventArgs e)
{
RootVisual = UnitTestSystem.CreateTestPage();
DispatcherHelper.Initialize();
}
Then I set this as the test (in the tests.cs):
[TestMethod]
public void TestMethod1()
{
Assert.IsNotNull(DispatcherHelper.UIDispatcher, "UI Dispatcher should not be null");
DispatcherHelper.CheckBeginInvokeOnUI(() =>
{
// Do nothing
var x = 1;
});
}
That worked for me. I even set a break point on the "var x = 1;" and it hit the breakpoint. Does this solve your problem? (if so please mark it as the answer).

Resources