|
| 1 | +# API Network Configuration for Android Development |
| 2 | + |
| 3 | +## Overview |
| 4 | + |
| 5 | +The FWH Location API and Marketing API are configured to listen on all network interfaces (`0.0.0.0`) during Development mode, allowing Android devices and emulators to connect via the host machine's IP address. |
| 6 | + |
| 7 | +## Configuration |
| 8 | + |
| 9 | +### Location API (FWH.Location.Api) |
| 10 | + |
| 11 | +**Ports:** |
| 12 | +- HTTP: `4748` (all interfaces in Development) |
| 13 | +- HTTPS: `4747` (all interfaces in Development) |
| 14 | + |
| 15 | +**Endpoints:** |
| 16 | +- Android Emulator: `http://10.0.2.2:4748` |
| 17 | +- Physical Android Device: `http://192.168.1.77:4748` (example, auto-detected) |
| 18 | +- Desktop/iOS: `https://localhost:4747` or `http://localhost:4748` |
| 19 | + |
| 20 | +### Marketing API (FWH.MarketingApi) |
| 21 | + |
| 22 | +**Ports:** |
| 23 | +- HTTP: `4750` (all interfaces in Development) |
| 24 | +- HTTPS: `4749` (all interfaces in Development) |
| 25 | + |
| 26 | +**Endpoints:** |
| 27 | +- Android Emulator: `http://10.0.2.2:4750` |
| 28 | +- Physical Android Device: `http://192.168.1.77:4750` (example, auto-detected) |
| 29 | +- Desktop/iOS: `https://localhost:4749` or `http://localhost:4750` |
| 30 | + |
| 31 | +## Implementation |
| 32 | + |
| 33 | +### Kestrel Configuration |
| 34 | + |
| 35 | +Both APIs use the following Kestrel configuration in `Program.cs`: |
| 36 | + |
| 37 | +```csharp |
| 38 | +if (builder.Environment.IsDevelopment()) |
| 39 | +{ |
| 40 | + builder.WebHost.ConfigureKestrel(options => |
| 41 | + { |
| 42 | + // Listen on all interfaces for HTTP |
| 43 | + options.ListenAnyIP(port); |
| 44 | + |
| 45 | + // Listen on all interfaces for HTTPS |
| 46 | + options.ListenAnyIP(httpsPort, listenOptions => |
| 47 | + { |
| 48 | + listenOptions.UseHttps(); |
| 49 | + }); |
| 50 | + }); |
| 51 | +} |
| 52 | +``` |
| 53 | + |
| 54 | +### Why `0.0.0.0`? |
| 55 | + |
| 56 | +**localhost (127.0.0.1):** |
| 57 | +- Only accepts connections from the same machine |
| 58 | +- Android devices/emulators cannot reach it from external network |
| 59 | + |
| 60 | +**0.0.0.0 (all interfaces):** |
| 61 | +- Accepts connections from any network interface |
| 62 | +- Allows Android emulators via `10.0.2.2` |
| 63 | +- Allows physical Android devices via LAN IP (e.g., `192.168.1.77`) |
| 64 | +- Still accepts `localhost` connections from the host machine |
| 65 | + |
| 66 | +## Security Considerations |
| 67 | + |
| 68 | +### Development Mode Only |
| 69 | + |
| 70 | +The `0.0.0.0` configuration is **only active in Development mode**: |
| 71 | + |
| 72 | +```csharp |
| 73 | +if (builder.Environment.IsDevelopment()) |
| 74 | +{ |
| 75 | + // Listen on 0.0.0.0 |
| 76 | +} |
| 77 | +``` |
| 78 | + |
| 79 | +In **Production**, APIs should: |
| 80 | +- Listen on specific interfaces or use reverse proxy |
| 81 | +- Enforce HTTPS with valid certificates |
| 82 | +- Implement proper authentication and authorization |
| 83 | +- Use API gateways and rate limiting |
| 84 | + |
| 85 | +### Local Network Exposure |
| 86 | + |
| 87 | +When listening on `0.0.0.0`, the APIs are accessible to: |
| 88 | +- ✅ Your development machine (localhost) |
| 89 | +- ✅ Devices on your local network (same Wi-Fi/Ethernet) |
| 90 | +- ❌ Internet (blocked by router/firewall) |
| 91 | + |
| 92 | +**Recommendations:** |
| 93 | +1. Use trusted networks only (home/office Wi-Fi) |
| 94 | +2. Avoid public Wi-Fi while developing |
| 95 | +3. Enable firewall rules if concerned about LAN exposure |
| 96 | +4. Use VPN for remote development if needed |
| 97 | + |
| 98 | +## Integration with Android IP Detection |
| 99 | + |
| 100 | +The Kestrel `0.0.0.0` configuration works in tandem with the Android MSBuild IP detection: |
| 101 | + |
| 102 | +### Build-Time IP Detection |
| 103 | + |
| 104 | +1. **MSBuild Target** (in `FWH.Mobile.Android.csproj`): |
| 105 | + - Detects host IP at build time |
| 106 | + - Injects IP into `appsettings.Development.json` |
| 107 | + - Example: `"HostIpAddress": "192.168.1.77"` |
| 108 | + |
| 109 | +2. **API Configuration** (in `Program.cs`): |
| 110 | + - APIs listen on `0.0.0.0:4748` and `0.0.0.0:4750` |
| 111 | + - Accept connections from any local network IP |
| 112 | + |
| 113 | +3. **Mobile App Connection**: |
| 114 | + - Loads config with detected IP |
| 115 | + - Connects to `http://192.168.1.77:4748` |
| 116 | + - API accepts connection because it listens on all interfaces |
| 117 | + |
| 118 | +### Connection Flow |
| 119 | + |
| 120 | +``` |
| 121 | +┌─────────────────────────────────────────────────────────────┐ |
| 122 | +│ 1. Developer builds Android app (DEBUG) │ |
| 123 | +│ MSBuild detects host IP: 192.168.1.77 │ |
| 124 | +│ Injects into appsettings.Development.json │ |
| 125 | +└────────────────────┬────────────────────────────────────────┘ |
| 126 | + │ |
| 127 | +┌────────────────────▼────────────────────────────────────────┐ |
| 128 | +│ 2. APIs start via Aspire AppHost │ |
| 129 | +│ Location API listens on 0.0.0.0:4748 │ |
| 130 | +│ Marketing API listens on 0.0.0.0:4750 │ |
| 131 | +└────────────────────┬────────────────────────────────────────┘ |
| 132 | + │ |
| 133 | +┌────────────────────▼────────────────────────────────────────┐ |
| 134 | +│ 3. Android app reads configuration │ |
| 135 | +│ LocationApiBaseUrl: http://192.168.1.77:4748 │ |
| 136 | +│ MarketingApiBaseUrl: http://192.168.1.77:4750 │ |
| 137 | +└────────────────────┬────────────────────────────────────────┘ |
| 138 | + │ |
| 139 | +┌────────────────────▼────────────────────────────────────────┐ |
| 140 | +│ 4. App makes HTTP request to 192.168.1.77:4748 │ |
| 141 | +│ Request reaches host via local network │ |
| 142 | +│ API accepts on 0.0.0.0:4748 │ |
| 143 | +│ Response returned to app │ |
| 144 | +└─────────────────────────────────────────────────────────────┘ |
| 145 | +``` |
| 146 | + |
| 147 | +## Troubleshooting |
| 148 | + |
| 149 | +### Android App Cannot Connect |
| 150 | + |
| 151 | +**Symptom:** |
| 152 | +- App shows connection errors |
| 153 | +- Timeout when accessing APIs |
| 154 | + |
| 155 | +**Diagnostic Steps:** |
| 156 | + |
| 157 | +1. **Check API is running:** |
| 158 | + ```powershell |
| 159 | + # Check if process is listening on port |
| 160 | + netstat -an | Select-String "4748" |
| 161 | + |
| 162 | + # Should show: 0.0.0.0:4748 LISTENING |
| 163 | + ``` |
| 164 | + |
| 165 | +2. **Verify IP detection:** |
| 166 | + ```powershell |
| 167 | + # Check what IP was detected |
| 168 | + cat src\FWH.Mobile\FWH.Mobile.Android\obj\appsettings.Development.processed.json |
| 169 | + |
| 170 | + # Confirm HostIpAddress matches your machine IP |
| 171 | + ipconfig |
| 172 | + ``` |
| 173 | + |
| 174 | +3. **Test API accessibility:** |
| 175 | + ```powershell |
| 176 | + # From your development machine |
| 177 | + curl http://localhost:4748/health |
| 178 | + |
| 179 | + # From Android device (if adb connected) |
| 180 | + adb shell curl http://192.168.1.77:4748/health |
| 181 | + ``` |
| 182 | + |
| 183 | +4. **Check firewall:** |
| 184 | + ```powershell |
| 185 | + # Windows Firewall might block ports |
| 186 | + # Add inbound rule for ports 4748, 4749, 4750 |
| 187 | + |
| 188 | + # Or temporarily disable for testing |
| 189 | + # (Not recommended for production) |
| 190 | + ``` |
| 191 | + |
| 192 | +### API Shows "Address Already in Use" |
| 193 | + |
| 194 | +**Symptom:** |
| 195 | +``` |
| 196 | +System.IO.IOException: Failed to bind to address http://0.0.0.0:4748: address already in use. |
| 197 | +``` |
| 198 | + |
| 199 | +**Solutions:** |
| 200 | + |
| 201 | +1. **Another process using the port:** |
| 202 | + ```powershell |
| 203 | + # Find process using port 4748 |
| 204 | + netstat -ano | Select-String "4748" |
| 205 | + |
| 206 | + # Kill the process (find PID from netstat output) |
| 207 | + taskkill /PID <pid> /F |
| 208 | + ``` |
| 209 | + |
| 210 | +2. **Previous API instance still running:** |
| 211 | + - Stop all running instances |
| 212 | + - Rebuild and restart via AppHost |
| 213 | + |
| 214 | +3. **Aspire orchestration conflict:** |
| 215 | + - Stop AppHost completely |
| 216 | + - Clean solution: `dotnet clean` |
| 217 | + - Rebuild: `dotnet build` |
| 218 | + - Start AppHost again |
| 219 | + |
| 220 | +### Wrong IP Detected |
| 221 | + |
| 222 | +**Symptom:** |
| 223 | +- IP in config doesn't match your network |
| 224 | +- App tries to connect to wrong address |
| 225 | + |
| 226 | +**Solutions:** |
| 227 | + |
| 228 | +1. **Multiple network adapters:** |
| 229 | + - Check `ipconfig` output |
| 230 | + - Identify correct adapter (Wi-Fi vs Ethernet vs VPN) |
| 231 | + - Use environment variables to override: |
| 232 | + ```powershell |
| 233 | + $env:LOCATION_API_BASE_URL = "http://192.168.1.77:4748/" |
| 234 | + dotnet build |
| 235 | + ``` |
| 236 | +
|
| 237 | +2. **VPN interfering:** |
| 238 | + - Disconnect VPN during development |
| 239 | + - Or use VPN IP if APIs need to be accessed over VPN |
| 240 | +
|
| 241 | +3. **Clean and rebuild:** |
| 242 | + ```powershell |
| 243 | + dotnet clean src/FWH.Mobile/FWH.Mobile.Android/FWH.Mobile.Android.csproj |
| 244 | + dotnet build src/FWH.Mobile/FWH.Mobile.Android/FWH.Mobile.Android.csproj -c Debug |
| 245 | + ``` |
| 246 | + |
| 247 | +## Testing |
| 248 | + |
| 249 | +### Verify API is listening on 0.0.0.0 |
| 250 | + |
| 251 | +```powershell |
| 252 | +# Start the AppHost |
| 253 | +dotnet run --project src/FWH.AppHost/FWH.AppHost.csproj |
| 254 | +
|
| 255 | +# In another terminal, check listening addresses |
| 256 | +netstat -an | Select-String "4748|4749|4750" |
| 257 | +
|
| 258 | +# Expected output (Windows): |
| 259 | +# TCP 0.0.0.0:4748 0.0.0.0:0 LISTENING |
| 260 | +# TCP 0.0.0.0:4747 0.0.0.0:0 LISTENING |
| 261 | +# TCP 0.0.0.0:4750 0.0.0.0:0 LISTENING |
| 262 | +# TCP 0.0.0.0:4749 0.0.0.0:0 LISTENING |
| 263 | +``` |
| 264 | + |
| 265 | +### Test from Different Sources |
| 266 | + |
| 267 | +```powershell |
| 268 | +# From localhost |
| 269 | +curl http://localhost:4748/health |
| 270 | +
|
| 271 | +# From LAN IP |
| 272 | +curl http://192.168.1.77:4748/health |
| 273 | +
|
| 274 | +# From Android emulator (using adb) |
| 275 | +adb shell curl http://10.0.2.2:4748/health |
| 276 | +``` |
| 277 | + |
| 278 | +All should return successful health check responses. |
| 279 | + |
| 280 | +## Environment-Specific Behavior |
| 281 | + |
| 282 | +| Environment | Listening Address | Accessible From | |
| 283 | +|------------|-------------------|-----------------| |
| 284 | +| **Development** | `0.0.0.0` | Localhost, LAN devices, Android emulator | |
| 285 | +| **Staging** | Configured via deployment | Typically behind load balancer/gateway | |
| 286 | +| **Production** | Configured via deployment | Public internet via reverse proxy/CDN | |
| 287 | + |
| 288 | +## Related Configuration Files |
| 289 | + |
| 290 | +- `src/FWH.Location.Api/Program.cs` - Location API Kestrel config |
| 291 | +- `src/FWH.MarketingApi/Program.cs` - Marketing API Kestrel config |
| 292 | +- `src/FWH.AppHost/Program.cs` - Aspire orchestration with port mappings |
| 293 | +- `src/FWH.Mobile/FWH.Mobile.Android/DetectHostIp.ps1` - IP detection script |
| 294 | +- `src/FWH.Mobile/FWH.Mobile.Android/FWH.Mobile.Android.csproj` - MSBuild target |
| 295 | +- `src/FWH.Mobile/FWH.Mobile/Configuration/ApiSettings.cs` - Mobile app config model |
| 296 | + |
| 297 | +## References |
| 298 | + |
| 299 | +- [Kestrel web server in ASP.NET Core](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/servers/kestrel) |
| 300 | +- [Configure endpoints for Kestrel](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/servers/kestrel/endpoints) |
| 301 | +- [Android Emulator Networking](https://developer.android.com/studio/run/emulator-networking) |
| 302 | +- [.NET Aspire overview](https://learn.microsoft.com/en-us/dotnet/aspire/get-started/aspire-overview) |
0 commit comments