You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
HMG_QLine/CORS_ISSUE_SOLUTION.md

7.7 KiB

CORS Issue - Web SignalR Connection & API Calls

Problem

ClientException: Failed to fetch, uri=https://ms.hmg.com/nscapi/PatientCallingHub/negotiate?IPAddress=10.71.50.53
ClientException: Failed to fetch, uri=https://ms.hmg.com/nscapi/api/PatientCall/Common_Config_GetByIP

What is CORS?

CORS (Cross-Origin Resource Sharing) is a browser security feature that blocks web apps from making requests to different domains unless the server explicitly allows it.

  • ✅ Mobile app: Works fine (no CORS restrictions)
  • ❌ Web app: Blocked by browser (CORS policy)

Why This Happens

The web app is trying to connect to:

https://ms.hmg.com/nscapi/PatientCallingHub  (SignalR Hub)
https://ms.hmg.com/nscapi/api/PatientCall/*   (REST APIs)
https://ms.hmg.com/nscapi/api/Gen/*           (Generic APIs)
https://ms.hmg.com/nscapi/api/Common/*        (Common APIs)

But the browser blocks it because:

  1. The web app is running on a different origin (e.g., http://localhost:port or http://device-ip:port)
  2. The server (ms.hmg.com) doesn't send CORS headers allowing the web app's origin

⚠️ IMPORTANT: CORS must be configured for ALL API endpoints, not just SignalR!

Solutions

The backend server needs to add CORS headers to allow web requests. The server admin needs to configure:

For ASP.NET Core (SignalR Hub + REST APIs):

In Startup.cs or Program.cs:

public void ConfigureServices(IServiceCollection services)
{
    // Add CORS policy - MUST be before other services
    services.AddCors(options =>
    {
        options.AddPolicy("AllowQLineWeb", builder =>
        {
            builder
                .WithOrigins(
                    "http://localhost:*",           // Development
                    "http://10.71.50.53:*",         // Device IP
                    "https://qline.hmg.com",        // Production
                    "https://your-web-domain.com"   // Your web domain
                )
                .AllowAnyHeader()
                .AllowAnyMethod()
                .AllowCredentials()                 // Required for SignalR
                .SetIsOriginAllowedToAllowWildcardSubdomains();
        });
    });

    // Add SignalR
    services.AddSignalR();
    
    // Add MVC/API Controllers
    services.AddControllers();
}

public void Configure(IApplicationBuilder app)
{
    // CRITICAL: Enable CORS BEFORE routing and endpoints
    app.UseCors("AllowQLineWeb");
    
    // Other middleware...
    app.UseRouting();
    app.UseAuthorization();
    
    app.UseEndpoints(endpoints =>
    {
        // Apply CORS to SignalR hub
        endpoints.MapHub<PatientCallingHub>("/PatientCallingHub")
            .RequireCors("AllowQLineWeb");
        
        // Apply CORS to API controllers (applies to ALL API routes)
        endpoints.MapControllers()
            .RequireCors("AllowQLineWeb");
    });
}

Alternative for Controllers (if endpoints not working):

Add [EnableCors("AllowQLineWeb")] to your controllers:

[ApiController]
[Route("api/[controller]")]
[EnableCors("AllowQLineWeb")]  // Add this to EACH controller
public class PatientCallController : ControllerBase
{
    // Your actions here...
}

For IIS:

Add to web.config:

<system.webServer>
    <httpProtocol>
        <customHeaders>
            <add name="Access-Control-Allow-Origin" value="*" />
            <add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />
            <add name="Access-Control-Allow-Headers" value="Content-Type, Authorization" />
            <add name="Access-Control-Allow-Credentials" value="true" />
        </customHeaders>
    </httpProtocol>
</system.webServer>

Solution 2: Run Web App from Same Domain

Deploy the web app to the same domain as the API:

  • API: https://ms.hmg.com/nscapi
  • Web App: https://ms.hmg.com/qline-web ✅ (Same origin, no CORS issue)

Solution 3: Use Reverse Proxy (Development)

For local development, use a reverse proxy to avoid CORS:

Using Flutter web with proxy:

  1. Create proxy_server.js:
const express = require('express');
const { createProxyMiddleware } = require('http-proxy-middleware');

const app = express();

app.use('/nscapi', createProxyMiddleware({
    target: 'https://ms.hmg.com',
    changeOrigin: true,
    ws: true,  // Proxy websockets for SignalR
}));

app.listen(3000, () => {
    console.log('Proxy running on http://localhost:3000');
});
  1. Update ApiConstants to use proxy:
static String baseUrl = kIsWeb ? 'http://localhost:3000/nscapi' : 'https://ms.hmg.com/nscapi';

Solution 4: Browser Extension (Development Only)

For testing, use a CORS browser extension:

  • Chrome: "CORS Unblock" or "Allow CORS"
  • Firefox: "CORS Everywhere"

⚠️ Warning: Only for development! Don't use in production.


Quick Test

To verify CORS is the issue, open browser console and run:

Test SignalR Hub:

fetch('https://ms.hmg.com/nscapi/PatientCallingHub/negotiate?IPAddress=10.71.50.53')
    .then(r => console.log('✅ SignalR CORS working!', r))
    .catch(e => console.error('❌ SignalR CORS blocked:', e));

Test Configuration API:

fetch('https://ms.hmg.com/nscapi/api/PatientCall/Common_Config_GetByIP', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ ipAddress: '10.71.50.53', apiKey: 'EE17D21C7943485D9780223CCE55DCE5' })
})
    .then(r => console.log('✅ Config API CORS working!', r))
    .catch(e => console.error('❌ Config API CORS blocked:', e));

Test Weather API:

fetch('https://ms.hmg.com/nscapi/api/PatientCall/WeatherForecast_GetBy5Days', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ cityID: '297030' })
})
    .then(r => console.log('✅ Weather API CORS working!', r))
    .catch(e => console.error('❌ Weather API CORS blocked:', e));

If you see "CORS blocked" errors, the server needs CORS configuration.


Current Status

  • ✅ IP persistence: FIXED (localStorage working)
  • ✅ IP retrieval on reload: FIXED
  • ❌ SignalR connection on web: BLOCKED BY CORS
  • ❌ REST API calls on web: BLOCKED BY CORS
  • ❌ Configuration API on web: BLOCKED BY CORS
  • ✅ All functionality on mobile: Working fine

IMPORTANT: The web app requires CORS for:

  1. SignalR Hub (/PatientCallingHub)
  2. Configuration API (/api/PatientCall/Common_Config_GetByIP)
  3. Weather API (/api/PatientCall/WeatherForecast_GetBy5Days)
  4. Prayer API (/api/PatientCall/PrayerTime_Today)
  5. RSS Feed API (/api/PatientCall/RssFeed_Get)
  6. Ticket APIs (/api/Common/*, /api/Gen/*)

All APIs must have CORS enabled for web deployment.


Next Steps

  1. Contact backend/server admin to add CORS headers for web app
  2. Provide them the allowed origins:
    • Development: http://localhost:*
    • Production: Your web app's domain
    • Device IPs: http://10.71.50.53:* (if needed)
  3. Test after server configuration is updated

Technical Details

Why Mobile Works:

  • Native apps use platform HTTP clients (URLSession, HttpURLConnection)
  • No browser, no CORS enforcement

Why Web Fails:

  • Web browsers enforce Same-Origin Policy
  • Requires server to send Access-Control-Allow-Origin header
  • SignalR needs Access-Control-Allow-Credentials: true

What the browser is blocking:

Request: http://localhost:xxxxx → https://ms.hmg.com/nscapi
Response missing: Access-Control-Allow-Origin: http://localhost:xxxxx
Result: ❌ BLOCKED

Date: August 2, 2026
Status: ⚠️ SERVER CONFIGURATION REQUIRED