Connecting WASM Apps to APIs: Overcoming CORS Challenges

Connecting WASM Apps to APIs: Overcoming CORS Challenges

Last week, I was diving into Uno Platform to understand its UI paradigms. What particularly caught my attention is Uno’s ability to render a webapp using WebAssembly (WASM). Having worked with WASM apps before, I’m all too familiar with the challenges of connecting to data sources and handling persistence within these applications.

My Previous WASM Struggles

About a year ago, I faced a significant challenge: connecting a desktop WebAssembly app to an old WCF webservice. Despite having the CORS settings correctly configured (or so I thought), I simply couldn’t establish a connection from the WASM app to the server. I spent days troubleshooting both the WCF service and another ASMX service, but both attempts failed. Eventually, I had to resort to webserver proxies to achieve my goal.

This experience left me somewhat traumatized by the mere mention of “connecting WASM with an API.” However, the time came to face this challenge again during my weekend experiments.

A Pleasant Surprise with Uno Platform

This weekend, I wanted to connect a XAF REST API to an Uno Platform client. To my surprise, it turned out to be incredibly straightforward. I successfully performed this procedure twice: once with a XAF REST API and once with the API included in the Uno app template. The ease of this integration was a refreshing change from my previous struggles.

Understanding CORS and Why It Matters for WASM Apps

To understand why my previous attempts failed and my recent ones succeeded, it’s important to grasp what CORS is and why it’s crucial for WebAssembly applications.

What is CORS?

CORS (Cross-Origin Resource Sharing) is a security feature implemented by web browsers that restricts web pages from making requests to a domain different from the one that served the original web page. It’s an HTTP-header based mechanism that allows a server to indicate which origins (domains, schemes, or ports) other than its own are permitted to load resources.

The Same-Origin Policy

Browsers enforce a security restriction called the “same-origin policy” which prevents a website from one origin from requesting resources from another origin. An origin consists of:

  • Protocol (HTTP, HTTPS)
  • Domain name
  • Port number

For example, if your website is hosted at https://myapp.com, it cannot make AJAX requests to https://myapi.com without the server explicitly allowing it through CORS.

Why CORS is Required for Blazor WebAssembly

Blazor WebAssembly (which uses similar principles to Uno Platform’s WASM implementation) is fundamentally different from Blazor Server in how it operates:

  1. Separate Deployment: Blazor WebAssembly apps are fully downloaded to the client’s browser and run entirely in the browser using WebAssembly. They’re typically hosted on a different server or domain than your API.
  2. Client-Side Execution: Since all code runs in the browser, when your Blazor WebAssembly app makes HTTP requests to your API, they’re treated as cross-origin requests if the API is hosted on a different domain, port, or protocol.
  3. Browser Security: Modern browsers block these cross-origin requests by default unless the server (your API) explicitly permits them via CORS headers.

Implementing CORS in Startup.cs

The solution to these CORS issues lies in properly configuring your server. In your Startup.cs file, you can configure CORS as follows:

public void ConfigureServices(IServiceCollection services) {
    services.AddCors(options => {
        options.AddPolicy("AllowBlazorApp",
            builder => {
                builder.WithOrigins("https://localhost:5000") // Replace with your Blazor app's URL
                       .AllowAnyHeader()
                       .AllowAnyMethod();
            });
    });

    // Other service configurations...
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env) {
    // Other middleware configurations...

    app.UseCors("AllowBlazorApp");

    // Other middleware configurations...
}

Conclusion

My journey with connecting WebAssembly applications to APIs has had its ups and downs. What once seemed like an insurmountable challenge has now become much more manageable, especially with platforms like Uno that simplify the process. Understanding CORS and implementing it correctly is crucial for successful WASM-to-API communication.

If you’re working with WebAssembly applications and facing similar challenges, I hope my experience helps you avoid some of the pitfalls I encountered along the way.

About Us

YouTube

https://www.youtube.com/c/JocheOjedaXAFXAMARINC

Our sites

Let’s discuss your XAF

https://www.udemy.com/course/microsoft-ai-extensions/

Our free A.I courses on Udemy

Bridging Traditional Development using XAF and AI: Training Sessions in Cairo

Bridging Traditional Development using XAF and AI: Training Sessions in Cairo

I recently had the privilege of conducting a training session in Cairo, Egypt, focusing on modern application development approaches. The session covered two key areas that are transforming how we build business applications: application frameworks and AI integration.

Streamlining Development with Application Frameworks

One of the highlights was demonstrating DevExpress’s eXpressApp Framework (XAF). The students were particularly impressed by how quickly we could build fully-functional Line of Business (LOB) applications. XAF’s approach eliminates much of the repetitive coding typically associated with business application development:

  • Automatic CRUD operations
  • Built-in security system
  • Consistent UI across different platforms
  • Rapid prototyping capabilities

Seamless Integration: XAF Meets Microsoft Semantic Kernel

What made this training unique was demonstrating how XAF’s capabilities extend into AI territory. We built the entire AI interface using XAF itself, showcasing how a traditional LOB framework can seamlessly incorporate advanced AI features. The audience, coming primarily from JavaScript backgrounds with Angular and React experience, was particularly impressed by how this approach simplified the integration of AI into business applications.

During the demonstrations, we explored practical implementations using Microsoft Semantic Kernel. The students were fascinated by practical demonstrations of:

  • Natural language processing for document analysis
  • Automated content generation for business documentation
  • Intelligent decision support systems
  • Context-aware data processing

Student Engagement and Outcomes

The response from the students, most of whom came from JavaScript development backgrounds, was overwhelmingly positive. As experienced frontend developers using Angular and React, they were initially skeptical about a different approach to application development. However, their enthusiasm peaked when they saw how these technologies could solve real business challenges they face daily. The combination of XAF’s rapid development capabilities and Semantic Kernel’s AI features, all integrated into a cohesive development experience, opened their eyes to new possibilities in application development.

Looking Forward

This training session in Cairo demonstrated the growing appetite for modern development approaches in the region. The intersection of efficient application frameworks and AI capabilities is proving to be a powerful combination for next-generation business applications.

And last, but not least, some pictures )))

 

 

Guide to Blazor Component Design and Implementation for backend devs

Guide to Blazor Component Design and Implementation for backend devs

Over time, I transitioned to using the first versions of my beloved framework, XAF. As you might know, XAF generates a polished and functional UI out of the box. Using XAF made me more of a backend developer since most of the development work wasn’t visual—especially in the early versions, where the model designer was rudimentary (it’s much better now).

Eventually, I moved on to developing .NET libraries and NuGet packages, diving deep into SOLID design principles. Fun fact: I actually learned about SOLID from DevExpress TV. Yes, there was a time before YouTube when DevExpress posted videos on technical tasks!

Nowadays, I feel confident creating and publishing my own libraries as NuGet packages. However, my “old monster” was still lurking in the shadows: UI components. I finally decided it was time to conquer it, but first, I needed to choose a platform. Here were my options:

  1. Windows Forms: A robust and mature platform but limited to desktop applications.
  2. WPF: A great option with some excellent UI frameworks that I love, but it still feels a bit “Windows Forms-ish” to me.
  3. Xamarin/Maui: I’m a big fan of Xamarin Forms and Xamarin/Maui XAML, but they’re primarily focused on device-specific applications.
  4. Blazor: This was the clear winner because it allows me to create desktop applications using Electron, embed components into Windows Forms, or even integrate with MAUI.

Recently, I’ve been helping my brother with a project in Blazor. (He’s not a programmer, but I am.) This gave me an opportunity to experiment with design patterns to get the most out of my components, which started as plain HTML5 pages.

Without further ado, here are the key insights I’ve gained so far.

Building high-quality Blazor components requires attention to both the C# implementation and Razor markup patterns. This guide combines architectural best practices with practical implementation patterns to create robust, reusable components.

1. Component Architecture and Organization

Parameter Organization

Start by organizing parameters into logical groups for better maintainability:

public class CustomForm : ComponentBase
{
    // Layout Parameters
    [Parameter] public string Width { get; set; }
    [Parameter] public string Margin { get; set; }
    [Parameter] public string Padding { get; set; }
    
    // Validation Parameters
    [Parameter] public bool EnableValidation { get; set; }
    [Parameter] public string ValidationMessage { get; set; }
    
    // Event Callbacks
    [Parameter] public EventCallback<bool> OnValidationComplete { get; set; }
    [Parameter] public EventCallback<string> OnSubmit { get; set; }
}

Corresponding Razor Template

<div class="form-container" style="width: @Width; margin: @Margin; padding: @Padding">
    <form @onsubmit="HandleSubmit">
        @if (EnableValidation)
        {
            <div class="validation-message">
                @ValidationMessage
            </div>
        }
        @ChildContent
    </form>
</div>

2. Smart Default Values and Template Composition

Component Implementation

public class DataTable<T> : ComponentBase
{
    [Parameter] public int PageSize { get; set; } = 10;
    [Parameter] public bool ShowPagination { get; set; } = true;
    [Parameter] public string EmptyMessage { get; set; } = "No data available";
    [Parameter] public IEnumerable<T> Items { get; set; } = Array.Empty<T>();
    [Parameter] public RenderFragment HeaderTemplate { get; set; }
    [Parameter] public RenderFragment<T> RowTemplate { get; set; }
    [Parameter] public RenderFragment FooterTemplate { get; set; }
}

Razor Implementation

<div class="table-container">
    @if (HeaderTemplate != null)
    {
        <header class="table-header">
            @HeaderTemplate
        </header>
    }
    
    <div class="table-content">
        @if (!Items.Any())
        {
            <div class="empty-state">@EmptyMessage</div>
        }
        else
        {
            @foreach (var item in Items)
            {
                @RowTemplate(item)
            }
        }
    </div>
    
    @if (ShowPagination)
    {
        <div class="pagination">
            <!-- Pagination implementation -->
        </div>
    }
</div>

3. Accessibility and Unique IDs

Component Implementation

public class FormField : ComponentBase
{
    private string fieldId = $"field-{Guid.NewGuid():N}";
    private string labelId = $"label-{Guid.NewGuid():N}";
    private string errorId = $"error-{Guid.NewGuid():N}";
    
    [Parameter] public string Label { get; set; }
    [Parameter] public string Error { get; set; }
    [Parameter] public bool Required { get; set; }
}

Razor Implementation

<div class="form-field">
    <label id="@labelId" for="@fieldId">
        @Label
        @if (Required)
        {
            <span class="required" aria-label="required">*</span>
        }
    </label>
    
    <input id="@fieldId" 
           aria-labelledby="@labelId"
           aria-describedby="@errorId"
           aria-required="@Required" />
    
    @if (!string.IsNullOrEmpty(Error))
    {
        <div id="@errorId" class="error-message" role="alert">
            @Error
        </div>
    }
</div>

4. Virtualization and Performance

Component Implementation

public class VirtualizedList<T> : ComponentBase
{
    [Parameter] public IEnumerable<T> Items { get; set; }
    [Parameter] public RenderFragment<T> ItemTemplate { get; set; }
    [Parameter] public int ItemHeight { get; set; } = 50;
    [Parameter] public Func<ItemsProviderRequest, ValueTask<ItemsProviderResult<T>>> ItemsProvider { get; set; }
}

Razor Implementation

<div class="virtualized-container" style="height: 500px; overflow-y: auto;">
    <Virtualize Items="@Items"
                ItemSize="@ItemHeight"
                ItemsProvider="@ItemsProvider"
                Context="item">
        <ItemContent>
            <div class="list-item" style="height: @(ItemHeight)px">
                @ItemTemplate(item)
            </div>
        </ItemContent>
        <Placeholder>
            <div class="loading-placeholder" style="height: @(ItemHeight)px">
                <div class="loading-animation"></div>
            </div>
        </Placeholder>
    </Virtualize>
</div>

Best Practices Summary

1. Parameter Organization

  • Group related parameters with clear comments
  • Provide meaningful default values
  • Use parameter validation where appropriate

2. Template Composition

  • Use RenderFragment for customizable sections
  • Provide default templates when needed
  • Enable granular control over component appearance

3. Accessibility

  • Generate unique IDs for form elements
  • Include proper ARIA attributes
  • Support keyboard navigation

4. Performance

  • Implement virtualization for large datasets
  • Use loading states and placeholders
  • Optimize rendering with appropriate conditions

Conclusion

Building effective Blazor components requires attention to both the C# implementation and Razor markup. By following these patterns and practices, you can create components that are:

  • Highly reusable
  • Performant
  • Accessible
  • Easy to maintain
  • Flexible for different use cases

Remember to adapt these practices to your specific needs while maintaining clean component design principles.