Search code examples
javascriptgeolocationblazorblazor-jsinterop

Get user geo-location in Blazor with JSInterop


I'm trying to get the user's city location, but first I want to try coordinates, as I find this hard enough already.

I have this javascript (from another post) but changed the return value;

<script>
window.getCoords = async () => {            
    const pos = await new Promise((resolve, reject) => {
        navigator.geolocation.getCurrentPosition(resolve, reject);
    });
        return (pos.coords.latitude, pos.coords.longitude);
    };
</script>

Assuming, I will get (double latitude, double longitude) back (correct me if I'm wrong). Also, I am not sure what the Promise keyword stands for, I'm assuming It's an old way for async...

After declaring this javascript in my _Host.cshtml file I go to my razor component. The component has the following;

@inject IJSRuntime JSRuntime
@using BrowserInterop.Geolocation;
protected override async Task<(double latitude, double longitude)> OnAfterRenderAsync(bool firstRender)
{

    if (firstRender)
    {
        var location = await JSRuntime.InvokeAsync<(double longitude, double lattitude)>("getCoords");
        Console.WriteLine("Lat: " + test.lattitude, " Long: " + test.longitude);

    }
//If geo-location fails default to IP-based location (this method works fine)
    return await GetIpGeolocationAsync();
}

However, once my program runs it crashes once it gets to var location = ... and I don't get the user location or an error to resolve this matter.

I have searched multiple examples, but all end up the same way. The MS docs also don't give an example on this, any guidance would be appreciated.


Solution

  • I use a service to call my js.

    Coordinate.cs

    public struct Coordinate
    {
        public double Latitude { get; set; }
    
        public double Longitude { get; set; }
    
        public double Accuracy { get; set; }
    }
    

    geoLocationJsInterop.js

    export function getCurrentPosition(dotNetHelper, enableHighAccuracy, maximumAge) {
    
        const options = {
            enableHighAccuracy: enableHighAccuracy,
            timeout: 5000,
            maximumAge: maximumAge
        };
    
        function success(position) {
    
            const coordinate = {
                latitude: position.coords.latitude,
                longitude: position.coords.longitude,
                accuracy: position.coords.accuracy
            };
    
            dotNetHelper.invokeMethodAsync('OnSuccessAsync', coordinate);
        }
    
        function error(error) {
    
            const errorDetails = {
                errorCode: error.code,
                errorMessage: error.message
            };
    
            dotNetHelper.invokeMethodAsync('OnErrorAsync', errorDetails);
        }
    
        navigator.geolocation.getCurrentPosition(success, error, options);
    }
    

    GeoLocationBroker.cs

    public class GeoLocationBroker : IGeoLocationBroker
    {
        private readonly IJSRuntime jsRuntime;
        private readonly Lazy<Task<IJSObjectReference>> moduleTask;
        private readonly DotNetObjectReference<GeoLocationBroker> dotNetObjectReference;
    
        public GeoLocationBroker(IJSRuntime jsRuntime)
        {
            this.jsRuntime = jsRuntime;
    
            moduleTask = new(() => this.jsRuntime!.InvokeAsync<IJSObjectReference>(
                identifier: "import",
                args: "./scripts/geoLocations/geoLocationJsInterop.js")
            .AsTask());
    
            dotNetObjectReference = DotNetObjectReference.Create(this);
        }
    
        public async ValueTask RequestGeoLocationAsync(bool enableHighAccuracy, int maximumAgeInMilliseconds)
        {
            var module = await moduleTask.Value;
            var dotNetObjectReference = this.dotNetObjectReference;
    
            await module.InvokeVoidAsync(identifier: "getCurrentPosition",
                                         dotNetObjectReference,
                                         enableHighAccuracy,
                                         maximumAgeInMilliseconds);
        }
    
        public async ValueTask RequestGeoLocationAsync()
        {
            await RequestGeoLocationAsync(enableHighAccuracy: true, maximumAgeInMilliseconds: 0);
        }
    
        public event Func<Coordinate, ValueTask> CoordinatesChanged = default!;
    
        public event Func<GeolocationPositionError, ValueTask> OnGeolocationPositionError = default!;
    
        [JSInvokable]
        public async Task OnSuccessAsync(Coordinate coordinates)
        {
            await CoordinatesChanged.Invoke(coordinates);
        }
    
        [JSInvokable]
        public async Task OnErrorAsync(GeolocationPositionError error)
        {
            await OnGeolocationPositionError.Invoke(error);
        }
    }
    

    Program.cs

    builder.Services.AddScoped<IGeoLocationBroker, GeoLocationBroker>();
    

    enter image description here