Problem to implement Visitors Hit Counter for my blazor server app!

Hamed Vaziri 136 Reputation points
2023-02-08T16:24:04.9166667+00:00

Hi everyone ..

To implement visitors hit counter for my blazor server app, i've created class to get current context of the page (via injecting ihttpContextAccessor) & extract some information such as url, querystring, etc, Then save these data to database.

The above class works correctly but i don't know where i should call it?

i've place it everywhere but each item have some problems!! for example, i've added to middleware, it works for requests, but not works for page navigations!

Also, i've placed in layout component (in both onInitialized & onAfterRender), but just firing for this url : "/_blazor" instead of actual page url!!

What's the problem & how to solve it?

What's best practice for this situation?

Thanks in advance

ASP.NET Core
ASP.NET Core
A set of technologies in the .NET Framework for building web applications and XML web services.
4,164 questions
Blazor
Blazor
A free and open-source web framework that enables developers to create web apps using C# and HTML being developed by Microsoft.
1,389 questions
0 comments No comments
{count} votes

Accepted answer
  1. Zhi Lv - MSFT 32,011 Reputation points Microsoft Vendor
    2023-02-14T08:43:26.6733333+00:00

    Hi @Hamed Vaziri

    i've created class to get current context of the page (via injecting ihttpContextAccessor) & extract some information such as url, querystring, etc, Then save these data to database. The above class works correctly but i don't know where i should call it?

    For security reasons, you must not use IHttpContextAccessor within Blazor apps. Blazor apps run outside of the context of the ASP.NET Core pipeline. The HttpContext isn't guaranteed to be available within the IHttpContextAccessor, and HttpContext isn't guaranteed to hold the context that started the Blazor app.

    So, to get the request url in Blazor application, you can try to use NavigationManager. Code like this:

    @page "/counter"
     
    @inject NavigationManager MyNavigationManager
    
    <PageTitle>Counter</PageTitle>
    <h1>Counter</h1>
    
    <p role="status">Current count: @currentCount</p>
    
    <button class="btn btn-primary" @onclick="IncrementCount">Click me</button> 
    <button class="btn btn-primary" @onclick="RemoveItem">Remove Item</button>
    
    @code {
        private int currentCount = 0;
        private void IncrementCount()
        {
            currentCount++;
        }
        protected override async Task OnInitializedAsync()
        { 
            var result = MyNavigationManager.Uri;
            //    #> https://localhost:7031/counter/3?q=hi
    
            var result2 = MyNavigationManager.BaseUri;
            //    #> https://localhost:7031/
    
        }
    }
    
    

    The result as below:

    User's image

    Besides, if you want to get current user information in Blazor, you can use the AuthenticationStateProvider service.


    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    Best regards,

    Dillion

    1 person found this answer helpful.
    0 comments No comments

2 additional answers

Sort by: Most helpful
  1. Bruce (SqlWork.com) 56,021 Reputation points
    2023-02-08T18:48:36.8166667+00:00

    for blazor server apps, there is only one server request. all blazor navigation is done via the signal/r connection. you should add hit tracking to each component. you will need to pass blazor navigation info to the tracker, as all blazor pages (unless a reload of the blazor app is done) are using the same HttpContext and HttpRequest.


  2. Hamed Vaziri 136 Reputation points
    2023-02-08T19:37:53.9+00:00

    Hi again!

    I've do your answer (place in AfterRender for each component), but i'm facing the same wrong result!

    Here is my hitCounter service class :

    public class HitCounterService
    {
    	private readonly AppDbContext _dbContext;
    	public HitCounterService(AppDbContext dbContext)
            {
                _dbContext = dbContext;
            }
    
    	public async Task InvokeAsync(HttpContext context)
    	{
    		if (context.Request.Path.Value.Contains("/_blazor"))
                    	return;
    		// Create object, Set properties & then save to db!
    	}
    }
    

    And here is DI at program.cs :

    builder.Services.AddTransient<HitCounterService>();
    

    And here is my code in each component to consume service :

    @page "/"
    @inject IHttpContextAccessor _contextAccessorService
    @inject HitCounterService _hitCounterService
    
    ...
    
    @code{
    	protected override async Task OnAfterRenderAsync(bool firstRender)
        	{
            	await _hitCounterService.InvokeAsync(_contextAccessorService.HttpContext);
        	}
    }
    

    But at runTime the method "InvokeAsync" has called only one time with url (/_blazor) instead of actual url!

    What's wrong?

    0 comments No comments