Uncategorized – GeoSaffer.com https://blog.geosaffer.com Apps, Electronics, 3D Printing & more Mon, 18 Nov 2024 23:36:42 +0000 en-US hourly 1 https://wordpress.org/?v=6.7.1 179389722 How to Implement and Use Google Translate API in C# https://blog.geosaffer.com/2024/11/19/how-to-implement-and-use-google-translate-api-in-c/?utm_source=rss&utm_medium=rss&utm_campaign=how-to-implement-and-use-google-translate-api-in-c https://blog.geosaffer.com/2024/11/19/how-to-implement-and-use-google-translate-api-in-c/#respond Tue, 19 Nov 2024 08:00:38 +0000 https://blog.geosaffer.com/?p=183 How to Implement and Use Google Translate API in C#

Welcome to this step-by-step tutorial on integrating the Google Translate API into your C# applications. Whether you’re building a multilingual application, need to translate user-generated content, or simply want to explore translation capabilities, this guide will help you get started.

Table of Contents

  1. Prerequisites
  2. Setting Up Google Cloud Translation API
  3. Creating a C# Project
  4. Writing the Code
  5. Running the Application
  6. Handling Common Issues
  7. Conclusion

1. Prerequisites

  • Google Cloud Account: You’ll need a Google Cloud account. If you don’t have one, you can create it here.
  • Basic Knowledge of C#: Familiarity with C# and .NET development.
  • Visual Studio: Install [Visual Studio](https://visualstudio.microsoft.com/) or any other C# IDE of your choice.

2. Setting Up Google Cloud Translation API

Before you can use the Google Translate API, you need to set it up in your Google Cloud account.

a. Create a New Project

  1. Go to the [Google Cloud Console](https://console.cloud.google.com/).
  2. Click on the project dropdown at the top and select New Project.
  3. Enter a project name and click Create.

b. Enable the Translation API

  1. Within your project in the Google Cloud Console, navigate to APIs & Services > Library.
  2. Search for “Cloud Translation API“.
  3. Select it and click Enable.

c. Create Service Account Credentials

  1. Go to APIs & Services > Credentials.
  2. Click on Create Credentials and select Service Account.
  3. Enter a service account name and description, then click Create.
  4. Assign the role Project > Editor (or a more restrictive role if preferred) and click Continue.
  5. Click Done.
  6. Find your newly created service account in the list, click the three dots on the right, and select Create key.
  7. Choose JSON as the key type and click Create. A JSON file will download to your computer. Keep this file secure!
Note: Do not expose your service account credentials publicly. Treat them like passwords.

3. Creating a C# Project

  1. Open Visual Studio.
  2. Click on Create a new project.
  3. Select Console App (.NET Core) or Console App (.NET Framework) based on your preference and click Next.
  4. Enter a project name (e.g., GoogleTranslateDemo) and click Create.

4. Writing the Code

Now, you’ll write the C# code to interact with the Google Translate API.

a. Install Required NuGet Packages

To use the Google Translate API, you need to install the Google.Cloud.Translation.V2 package.

  1. In Visual Studio, right-click on your project in the Solution Explorer and select Manage NuGet Packages….
  2. Go to the Browse tab, search for Google.Cloud.Translation.V2, select it, and click Install.

b. Add the Service Account Key

  1. Copy the downloaded JSON key file into your project directory.
  2. In Visual Studio, right-click on the JSON file in the Solution Explorer, select Properties, and set Copy to Output Directory to Copy if newer.

c. Implement the Translation Logic

Replace the content of Program.cs with the following code:

using System;
using Google.Cloud.Translation.V2;

namespace GoogleTranslateDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            // Set the environment variable for authentication
            // Replace 'path-to-your-json-key-file.json' with the actual path
            Environment.SetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS", "path-to-your-json-key-file.json");

            // Create a client
            TranslationClient client = TranslationClient.Create();

            // Example text
            string text = "Hello, how are you today?";

            // Detect language
            var detection = client.DetectLanguage(text);
            Console.WriteLine($"Detected Language: {detection.Language} (Confidence: {detection.Confidence:P})");

            // Translate text to Spanish
            var translation = client.TranslateText(text, "es");
            Console.WriteLine($"\nTranslated Text to Spanish: {translation.TranslatedText}");

            // Translate text from Spanish back to English
            string spanishText = translation.TranslatedText;
            var translatedBack = client.TranslateText(spanishText, "en", "es");
            Console.WriteLine($"\nTranslated Back to English: {translatedBack.TranslatedText}");
        }
    }
}

d. Understanding the Code

  • Authentication: The environment variable GOOGLE_APPLICATION_CREDENTIALS is set to the path of your JSON key file. This allows the application to authenticate with Google Cloud.
  • TranslationClient: This client is used to interact with the Translation API.
  • DetectLanguage: Detects the language of the provided text.
  • TranslateText: Translates the provided text to the specified target language.
Note: Ensure that the path to your JSON key file is correct. You can use an absolute path or a relative path based on your project structure.

5. Running the Application

  1. Save all your changes in Visual Studio.
  2. Press F5 or click on Start to run the application.

Expected Output:


Detected Language: en (Confidence: 99.00%)

Translated Text to Spanish: Hola, ¿cómo estás hoy?

Translated Back to English: Hello, how are you today?

6. Handling Common Issues

a. Authentication Errors

If you encounter authentication errors, ensure that:

  • The GOOGLE_APPLICATION_CREDENTIALS environment variable points to the correct JSON key file.
  • The service account has the necessary permissions to use the Translation API.

b. Quota Exceeded

Google Cloud Translation API has usage quotas. If you exceed these quotas:

  • Check your [Google Cloud Quotas](https://console.cloud.google.com/iam-admin/quotas).
  • Consider requesting a quota increase if necessary.

c. Encoding Issues

If translations appear as question marks (????), ensure that:

  • Your console supports UTF-8 encoding.
  • Use fonts that support the characters of the target language.
Tip: For better security, avoid hardcoding the path to your JSON key file. Instead, set the environment variable outside the application or use secure secret management.

7. Conclusion

Congratulations! You’ve successfully integrated the Google Translate API into your C# application. This setup allows you to detect languages and translate text between multiple languages seamlessly.

Feel free to explore more features of the Google Cloud Translation API, such as batch translations, glossary support, and more to enhance your application’s multilingual capabilities.

If you encounter any issues or have questions, refer to the official [Google Cloud Translation API Documentation](https://cloud.google.com/translate/docs) or seek help from the community.

 

]]>
https://blog.geosaffer.com/2024/11/19/how-to-implement-and-use-google-translate-api-in-c/feed/ 0 183
Implementing Authentication in a .NET 9 MAUI Blazor Hybrid App https://blog.geosaffer.com/2024/11/18/180/?utm_source=rss&utm_medium=rss&utm_campaign=180 https://blog.geosaffer.com/2024/11/18/180/#respond Mon, 18 Nov 2024 03:24:04 +0000 https://blog.geosaffer.com/?p=180

Implementing Authentication in a .NET 9 MAUI Blazor Hybrid App

This guide provides detailed steps to implement a basic username and password authentication system in a .NET 9 MAUI Blazor Hybrid app using the new Blazor Web App template with a .Shared project. The authentication system uses a simple in-memory user store for demonstration purposes.


Table of Contents

  1. Project Structure Overview
  2. Prerequisites
  3. Step-by-Step Implementation
  4. Additional Considerations
  5. Conclusion

Project Structure Overview

Your solution will consist of three projects:

  • YourApp.Web: The Blazor Web App project.
  • YourApp.Mobile: The MAUI Blazor Hybrid project.
  • YourApp.Shared: Contains shared components, pages, and services.

Prerequisites

  • .NET 9 SDK: Ensure that you have the .NET 9 SDK installed.
  • Visual Studio 2022 (17.7 or later): For project creation and development.
  • MAUI Workload: Install the MAUI workload for cross-platform development.
  • Install the following Nuget Packages
      • In the .SharedProject
        • Microsoft.AspNetCore.Authorization (9.0.0)
        • Microsoft.AspNetCore.Components.Authorization (9.0.0)
        • Microsoft.AspNetCore.Components.Web (9.0.0)
        • Microsoft.Maui.Essentials (9.0.10)

Step-by-Step Implementation

Create a New Solution

  1. Open Visual Studio 2022.
  2. Create a New Project:
    • Template: Search for Blazor Web App.
    • Project Name: Enter YourApp.Web.
    • Solution Name: Enter YourApp.
  3. Add a MAUI Blazor App:
    • Right-click on the solution in Solution Explorer.
    • Select Add > New Project.
    • Choose .NET MAUI Blazor App.
    • Project Name: Enter YourApp.Mobile.
  4. Add a Class Library for Shared Code:
    • Right-click on the solution.
    • Select Add > New Project.
    • Choose Class Library.
    • Project Name: Enter YourApp.Shared.
  5. Add References:
    • In YourApp.Web and YourApp.Mobile, add a reference to YourApp.Shared.
  6. Set Up the Projects:
    • Ensure all projects target .NET 9.
    • Update the .csproj files if necessary.

Add some global usings for razor pages

In YourApp.Shared, open and edit _Imports.razor and add the following usings:


@using System.Net.Http
@using System.Net.Http.Json
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using static Microsoft.AspNetCore.Components.Web.RenderMode
@using Microsoft.AspNetCore.Components.Web.Virtualization
@using Microsoft.JSInterop

@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.Authorization;

@using YourApp.Shared.Layout
@using YourApp.Shared.Pages
@using YourApp.Shared.Services

Implement the Authentication State Provider

Create CustomAuthenticationStateProvider

In YourApp.Shared, create a new folder called Services and add the following class:


// YourApp.Shared/Services/CustomAuthenticationStateProvider.cs
using Microsoft.AspNetCore.Components.Authorization;
using System.Security.Claims;
using System.Threading.Tasks;

namespace YourApp.Shared.Services
{
    public class CustomAuthenticationStateProvider : AuthenticationStateProvider
    {
        private ClaimsPrincipal _anonymous = new ClaimsPrincipal(new ClaimsIdentity());
        private ClaimsPrincipal _currentUser;

        public override Task<AuthenticationState> GetAuthenticationStateAsync()
        {
            return Task.FromResult(new AuthenticationState(_currentUser ?? _anonymous));
        }

        public void SignIn(string username)
        {
            var identity = new ClaimsIdentity(new[]
            {
                new Claim(ClaimTypes.Name, username)
            }, "apiauth_type");

            _currentUser = new ClaimsPrincipal(identity);
            NotifyAuthenticationStateChanged(GetAuthenticationStateAsync());
        }

        public void SignOut()
        {
            _currentUser = _anonymous;
            NotifyAuthenticationStateChanged(GetAuthenticationStateAsync());
        }
    }
}

Register the Authentication State Provider

In YourApp.Web/Program.cs:


using YourApp.Shared.Services;
using Microsoft.AspNetCore.Components.Authorization;

var builder = WebApplication.CreateBuilder(args);

// Register services
builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();

builder.Services.AddScoped<CustomAuthenticationStateProvider>();
builder.Services.AddScoped<AuthenticationStateProvider>(provider =>
    provider.GetRequiredService<CustomAuthenticationStateProvider>());
builder.Services.AddAuthorizationCore();

var app = builder.Build();

// Configure middleware
app.UseStaticFiles();
app.UseRouting();

app.MapBlazorHub();
app.MapFallbackToPage("/_Host");

app.Run();

In YourApp.Mobile/MauiProgram.cs:


using YourApp.Shared.Services;
using Microsoft.AspNetCore.Components.Authorization;

public static class MauiProgram
{
    public static MauiApp CreateMauiApp()
    {
        var builder = MauiApp.CreateBuilder();

        builder.UseMauiApp<App>();

        // Register services
        builder.Services.AddMauiBlazorWebView();
#if DEBUG
        builder.Services.AddBlazorWebViewDeveloperTools();
#endif

        builder.Services.AddScoped<CustomAuthenticationStateProvider>();
        builder.Services.AddScoped<AuthenticationStateProvider>(provider =>
            provider.GetRequiredService<CustomAuthenticationStateProvider>());
        builder.Services.AddAuthorizationCore();

        return builder.Build();
    }
}

Implement a Simple User Store

Create UserService.cs in YourApp.Shared/Services:


// YourApp.Shared/Services/UserService.cs
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace YourApp.Shared.Services
{
    public class UserService
    {
        private List<UserCredential> _users = new List<UserCredential>
        {
            new UserCredential { Username = "user1", Password = "password1", Role = "User" },
            new UserCredential { Username = "admin", Password = "admin123", Role = "Admin" }
        };

        public Task<UserCredential> AuthenticateUserAsync(string username, string password)
        {
            var user = _users.FirstOrDefault(u => u.Username == username && u.Password == password);
            return Task.FromResult(user);
        }
    }

    public class UserCredential
    {
        public string Username { get; set; }
        public string Password { get; set; }
        public string Role { get; set; }
    }
}

Register UserService in both Program.cs and MauiProgram.cs:


builder.Services.AddScoped<UserService>();

Build Login and Logout Components

Create Login.razor

In YourApp.Shared/Pages:


@page "/login"
@using YourApp.Shared.Services
@inject CustomAuthenticationStateProvider AuthStateProvider
@inject UserService UserService
@inject NavigationManager NavigationManager

<h3>Login</h3>

@if (!string.IsNullOrEmpty(ErrorMessage))
{
    <div class="alert alert-danger">@ErrorMessage</div>
}

<EditForm Model="loginModel" OnValidSubmit="HandleLogin">
    <DataAnnotationsValidator />
    <ValidationSummary />

    <div>
        <label>Username:</label>
        <InputText @bind-Value="loginModel.Username" />
    </div>
    <div>
        <label>Password:</label>
        <InputText type="password" @bind-Value="loginModel.Password" />
    </div>
    <button type="submit">Login</button>
</EditForm>

@code {
    private LoginModel loginModel = new LoginModel();
    private string ErrorMessage;

    private async Task HandleLogin()
    {
        var user = await UserService.AuthenticateUserAsync(loginModel.Username, loginModel.Password);
        if (user != null)
        {
            AuthStateProvider.SignIn(user.Username);
            NavigationManager.NavigateTo("/");
        }
        else
        {
            ErrorMessage = "Invalid username or password.";
        }
    }

    public class LoginModel
    {
        public string Username { get; set; }
        public string Password { get; set; }
    }
}

Create Logout.razor

In YourApp.Shared/Pages:


@page "/logout"
@inject CustomAuthenticationStateProvider AuthStateProvider
@inject NavigationManager NavigationManager

<h3>Logging out...</h3>

@code {
    protected override void OnInitialized()
    {
        AuthStateProvider.SignOut();
        NavigationManager.NavigateTo("/");
    }
}

Protect Pages with Authorization

Create a Protected Page

Create ProtectedPage.razor in YourApp.Shared/Pages:


@page "/protected"
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.Authorization
@attribute [Authorize]
@inject AuthenticationStateProvider AuthenticationStateProvider

<h3>Protected Page</h3>

<p>Welcome, @userName!</p>

@code {
    private string userName;

    protected override async Task OnInitializedAsync()
    {
        var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
        var user = authState.User;
        userName = user.Identity?.Name;
    }
}

Ensure Required Packages Are Installed

Add the following NuGet packages to YourApp.Shared:

  • Microsoft.AspNetCore.Authorization
  • Microsoft.AspNetCore.Components.Authorization

Update the Navigation Menu

In YourApp.Shared/Shared, update NavMenu.razor:


@inject AuthenticationStateProvider AuthenticationStateProvider
@implements IDisposable

<nav>
    <ul>
        <li><NavLink href="/">Home</NavLink></li>
        @if (isAuthenticated)
        {
            <li><NavLink href="protected">Protected Page</NavLink></li>
            <li><NavLink href="logout">Logout (@userName)</NavLink></li>
        }
        else
        {
            <li><NavLink href="login">Login</NavLink></li>
        }
    </ul>
</nav>

@code {
    private bool isAuthenticated;
    private string userName;
    private AuthenticationState authenticationState;

    protected override async Task OnInitializedAsync()
    {
        authenticationState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
        UpdateAuthenticationState(authenticationState);

        AuthenticationStateProvider.AuthenticationStateChanged += OnAuthenticationStateChanged;
    }

    private void UpdateAuthenticationState(AuthenticationState authState)
    {
        var user = authState.User;
        isAuthenticated = user.Identity?.IsAuthenticated ?? false;
        userName = user.Identity?.Name;
        StateHasChanged();
    }

    private void OnAuthenticationStateChanged(Task<AuthenticationState> task)
    {
        InvokeAsync(async () =>
        {
            var authState = await task;
            UpdateAuthenticationState(authState);
        });
    }

    public void Dispose()
    {
        AuthenticationStateProvider.AuthenticationStateChanged -= OnAuthenticationStateChanged;
    }
}

Adjust Routing in Routes.razor

In YourApp.Shared, update Routes.razor:


@using Microsoft.AspNetCore.Components.Authorization
@using Microsoft.AspNetCore.Components.Routing

<CascadingAuthenticationState>
    <Router AppAssembly="@typeof(Routes).Assembly">
        <Found Context="routeData">
            <AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)">
                <NotAuthorized>
                    @if (context.User.Identity.IsAuthenticated)
                    {
                        <p>You are not authorized to access this resource.</p>
                    }
                    else
                    {
                        <RedirectToLogin />
                    }
                </NotAuthorized>
                <Authorizing>
                    <p>Authorizing...</p>
                </Authorizing>
            </AuthorizeRouteView>
        </Found>
        <NotFound>
            <LayoutView Layout="@typeof(MainLayout)">
                <p>Sorry, there's nothing at this address.</p>
            </LayoutView>
        </NotFound>
    </Router>
</CascadingAuthenticationState>

@code {
    [CascadingParameter]
    private Task<AuthenticationState> authenticationStateTask { get; set; }

    private AuthenticationState context => authenticationStateTask.Result;
}

Create RedirectToLogin.razor

In YourApp.Shared/Components:


@inject NavigationManager NavigationManager

@code {
    protected override void OnInitialized()
    {
        var returnUrl = Uri.EscapeDataString(NavigationManager.Uri);
        NavigationManager.NavigateTo($"/login?returnUrl={returnUrl}");
    }
}

Test the Application

Run the Web App

  1. Start the Web Project (YourApp.Web).
  2. Navigate to a Protected Page: Visit /protected.
  3. Verify Redirection: You should be redirected to the login page.
  4. Log In: Use user1 / password1.
  5. Access Protected Content: You should now see the protected page.

Run the Mobile App

  1. Start the Mobile Project (YourApp.Mobile).
  2. Repeat the Steps: Perform the same steps as above to verify authentication on mobile.

Additional Considerations

Persisting Authentication State

To persist authentication state across sessions, modify the CustomAuthenticationStateProvider to use secure storage.

Implementing Secure Storage

Update CustomAuthenticationStateProvider.cs:


using Microsoft.JSInterop;
using System.Text.Json;
using Microsoft.Maui.Storage;

public class CustomAuthenticationStateProvider : AuthenticationStateProvider
{
    private readonly IJSRuntime _jsRuntime;
    private const string _authDataKey = "authData";
    private ClaimsPrincipal _currentUser;

    public CustomAuthenticationStateProvider(IJSRuntime jsRuntime = null)
    {
        _jsRuntime = jsRuntime;
    }

    public override async Task<AuthenticationState> GetAuthenticationStateAsync()
    {
        if (_currentUser != null)
        {
            return new AuthenticationState(_currentUser);
        }

        string authDataJson = null;

#if ANDROID || IOS || WINDOWS
        authDataJson = await SecureStorage.Default.GetAsync(_authDataKey);
#else
        if (_jsRuntime != null)
        {
            authDataJson = await _jsRuntime.InvokeAsync<string>("localStorage.getItem", _authDataKey);
        }
#endif

        if (!string.IsNullOrWhiteSpace(authDataJson))
        {
            var authData = JsonSerializer.Deserialize<AuthData>(authDataJson);
            var identity = new ClaimsIdentity(new[]
            {
                new Claim(ClaimTypes.Name, authData.Username)
            }, "apiauth_type");

            _currentUser = new ClaimsPrincipal(identity);
        }
        else
        {
            _currentUser = new ClaimsPrincipal(new ClaimsIdentity());
        }

        return new AuthenticationState(_currentUser);
    }

    public async void SignIn(string username)
    {
        var identity = new ClaimsIdentity(new[]
        {
            new Claim(ClaimTypes.Name, username)
        }, "apiauth_type");

        _currentUser = new ClaimsPrincipal(identity);

        var authData = new AuthData { Username = username };
        var authDataJson = JsonSerializer.Serialize(authData);

#if ANDROID || IOS || WINDOWS
        await SecureStorage.Default.SetAsync(_authDataKey, authDataJson);
#else
        if (_jsRuntime != null)
        {
            await _jsRuntime.InvokeVoidAsync("localStorage.setItem", _authDataKey, authDataJson);
        }
#endif

        NotifyAuthenticationStateChanged(GetAuthenticationStateAsync());
    }

    public async void SignOut()
    {
        _currentUser = new ClaimsPrincipal(new ClaimsIdentity());

#if ANDROID || IOS || WINDOWS
        SecureStorage.Default.Remove(_authDataKey);
#else
        if (_jsRuntime != null)
        {
            await _jsRuntime.InvokeVoidAsync("localStorage.removeItem", _authDataKey);
        }
#endif

        NotifyAuthenticationStateChanged(GetAuthenticationStateAsync());
    }

    private class AuthData
    {
        public string Username { get; set; }
    }
}

Enhancing Security

  • Password Hashing: Implement hashing for passwords instead of storing them in plain text.
  • Use HTTPS: Ensure your web application uses HTTPS to encrypt data in transit.
  • Input Validation: Validate all user inputs to prevent injection attacks.

Conclusion

By following these steps, you’ve successfully implemented a basic authentication system in your .NET 9 MAUI Blazor Hybrid app using the new Blazor Web App template with a .Shared project. This setup allows you to:

  • Understand the Basics: Gain insights into how authentication works in Blazor and MAUI.
  • Share Code: Use the .Shared project to share components and services between web and mobile apps.
  • Prepare for Future Enhancements: Lay the groundwork for integrating more secure and complex authentication mechanisms in the future.

Next Steps:

  • Implement Secure Authentication: Consider integrating OAuth or OpenID Connect for robust authentication.
  • Role-Based Authorization: Utilize roles to manage user access to different parts of the application.
  • UI/UX Improvements: Enhance the user interface for better usability and aesthetics.

Feel free to customize this guide further or reach out if you have any questions or need additional assistance!

]]>
https://blog.geosaffer.com/2024/11/18/180/feed/ 0 180
Bluetooth Thermometer app – some new added features. https://blog.geosaffer.com/2021/01/04/add-some-new-features-to-the-bluetooth-thermometer-app/?utm_source=rss&utm_medium=rss&utm_campaign=add-some-new-features-to-the-bluetooth-thermometer-app Mon, 04 Jan 2021 22:07:02 +0000 https://blog.geosaffer.com/?p=174 Here is a video on the added features of the Bluetooth thermometer app

https://youtu.be/z5OnSWrEYCc

]]>
174