0

I have the _Host.cshtml.cs file. The code is executed before any page is loaded. Blazor by default will load the page with a matching @page header. But I detected something in HttpContext and I want take the user who requested the "/" URL to another default location. A redirection, but in code.

  1. Redirection should occur before any page is loaded (should load my special page).
  2. Should not affect normal site operation (header criteria not met - default page loaded, default routing)

I need it for a mobile version of my application. I detect mobile browsers. Done. I even create different menu in my MainLayout. Done. Now I just want the other page to be default for mobile users.

I have following code:

if (_httpContextAccssor.HttpContext.Request.Path == "/")
                _httpContextAccssor.HttpContext.Request.Path = "/m_index";

It works, but the page is displayed for like a half of a second, then I'm redirected again to "/".

The app uses Identity to log in users and redirect to the login page. I have a hunch it's somehow related to it, but I'm not sure how. When a user is not logged in he or she is redirected to the login page. Then "/" page is loaded. The problem is the user is already logged in (cookie), the login page doesn't show, but still I'm redirected from the page I set in the Request.Path.

Harry
  • 4,524
  • 4
  • 42
  • 81

1 Answers1

0

OK, got it. I could delete the question, but maybe someone would stumble upon the similar problem.

First things first: How to use the HttpContext object in server-side Blazor to retrieve information about the user, user agent

Here's what I've started from. I needed to detect a mobile device, it worked as charm (with a few modifications, irrelevant now).

The important part is that _Host.cshtml.cs example. In the link I pasted there is description how to access the HttpContext of the request. And one more important thing - how to pass parameters from the host to the main App.razor component.

So I just wondered - what if I made a redirection there, in the App?

So, my App:

using Microsoft.AspNetCore.Components;
using System;

namespace Example {

    public partial class App : IDisposable {

        [Inject] NavigationManager NavMan { get; set; }

        [Parameter] public bool IsMobile { get; set; }

        void LocationChangeEventHandler(object sender, EventArgs eventArgs) => ScriptableComponentBase.ResetInstanceCounter();

        protected override void OnInitialized() {
            base.OnInitialized();
            NavMan.LocationChanged += LocationChangeEventHandler;
            var localPath = new Uri(NavMan.Uri).LocalPath;
            if (IsMobile && localPath == "/") NavMan.NavigateTo("/m_index");
        }

        public void Dispose() => NavMan.LocationChanged -= LocationChangeEventHandler;

    }

}

Holup... How do I get IsMobile parameter?

Here, my relevant _Host.cshtml fragment:

<app>
    <component type="typeof(App)" render-mode="ServerPrerendered" param-IsMobile="@Model.IsMobile" />
</app>

Wait, but where does the Model come from? From the linked example. Here's mine _Host.cshtml.cs:

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.RazorPages;
using System.Text.RegularExpressions;
using Microsoft.AspNetCore.Components;

namespace Example.Pages {

    /// <summary>
    /// Allows access HttpContext to detect mobile requests.
    /// <see href="https://stackoverflow.com/questions/59538318/how-to-use-the-httpcontext-object-in-server-side-blazor-to-retrieve-information" />
    /// </summary>
    public class HostModel : PageModel {
        
        private readonly IHttpContextAccessor _httpContextAccssor;
        private readonly Regex RxMobileUATest = new Regex(@"(iPhone|Android|Mini|Mobile|Puffin)", RegexOptions.Compiled);

        public HostModel(IHttpContextAccessor httpContextAccssor, NavigationManager navigationManager) => _httpContextAccssor = httpContextAccssor;

        public string UserAgent { get; private set; }
        
        public string IPAddress { get; private set; }

        public bool IsMobile { get; private set; }

        public void OnGet() {
            UserAgent = _httpContextAccssor.HttpContext.Request.Headers["User-Agent"];
            IPAddress = _httpContextAccssor.HttpContext.Connection.RemoteIpAddress.ToString();
            IsMobile = RxMobileUATest.IsMatch(UserAgent);
        }
    
    }

}

It all looks a little bit chaotic, but it shows the direction of my investigation. First I've checked if I can redirect the main page ("/" request) to a random other page in the App component. To my greatest surprise I could. The rest seemed to be easy having the knowledge from the link. So - I needed my app to know, if the request comes from a mobile browser. I've seen in linked example, that a parameter can be passed to the App component. I just needed to get the value. So I needed to access HttpContext of the request to get the headers from the browser, that can be done like in linked example: basically you create a model for the _Host.cshtml page. You have also to add services.AddHttpContextAccessor(); to your Startup.ConfigureServices() method. Having the context - detecting the mobile browsers by UserAgent header is a piece of cake. You can totally ignore all weird cases. If a mobile browser doesn't want mobile content - fine, we serve desktop. If the mobile browser doesn't want to announce it's a mobile browser like most mobile browsers do - we serve desktop.

Look mum, no JavaScript! ;)

Harry
  • 4,524
  • 4
  • 42
  • 81