|
| 1 | +using System; |
| 2 | +using System.Collections.Generic; |
| 3 | +using System.IO; |
| 4 | + |
| 5 | +namespace Microsoft.AspNetCore.Components.WebView.Maui |
| 6 | +{ |
| 7 | + /// <summary> |
| 8 | + /// Provides the seam that lets a handler implementing <see cref="IBlazorWebViewHandler"/> participate in |
| 9 | + /// MAUI Blazor static content hot reload, which serves updated <c>wwwroot</c> assets (most notably CSS) |
| 10 | + /// without restarting the app. |
| 11 | + /// </summary> |
| 12 | + /// <remarks> |
| 13 | + /// A handler participates in two places, mirroring what the built-in handlers do: |
| 14 | + /// <list type="number"> |
| 15 | + /// <item><description> |
| 16 | + /// Call <see cref="AttachToWebViewManagerIfEnabled(WebViewManager)"/> once, right after creating its |
| 17 | + /// <see cref="WebViewManager"/> and before navigating, so the notifier root component is registered. |
| 18 | + /// </description></item> |
| 19 | + /// <item><description> |
| 20 | + /// Call <see cref="TryReplaceResponseContent(string, string, ref int, ref Stream, IDictionary{string, string})"/> |
| 21 | + /// while resolving a static content request, so hot-reloaded content replaces the on-disk content. |
| 22 | + /// </description></item> |
| 23 | + /// </list> |
| 24 | + /// Both members are no-ops when hot reload is unavailable (that is, when |
| 25 | + /// <see cref="System.Reflection.Metadata.MetadataUpdater.IsSupported"/> is <see langword="false"/>), so |
| 26 | + /// handlers can call them unconditionally. Static content hot reload is a development-time feature and is |
| 27 | + /// independent of Razor component hot reload, which does not require any handler participation. |
| 28 | + /// </remarks> |
| 29 | + public static class BlazorWebViewStaticContentHotReload |
| 30 | + { |
| 31 | + /// <summary> |
| 32 | + /// Registers the static content hot reload notifier with the specified <see cref="WebViewManager"/> |
| 33 | + /// when hot reload is supported by the current runtime; otherwise does nothing. |
| 34 | + /// </summary> |
| 35 | + /// <param name="webViewManager">The <see cref="WebViewManager"/> to attach to.</param> |
| 36 | + /// <remarks> |
| 37 | + /// Call this once per <see cref="WebViewManager"/> instance, after construction and before navigating. |
| 38 | + /// Calling it more than once for the same manager throws, because the notifier uses a fixed root |
| 39 | + /// component selector. |
| 40 | + /// </remarks> |
| 41 | + /// <exception cref="ArgumentNullException">Thrown if <paramref name="webViewManager"/> is <see langword="null"/>.</exception> |
| 42 | + public static void AttachToWebViewManagerIfEnabled(WebViewManager webViewManager) |
| 43 | + { |
| 44 | + ArgumentNullException.ThrowIfNull(webViewManager); |
| 45 | + |
| 46 | + StaticContentHotReloadManager.AttachToWebViewManagerIfEnabled(webViewManager); |
| 47 | + } |
| 48 | + |
| 49 | + /// <summary> |
| 50 | + /// Replaces the response for a static content request with hot-reloaded content when an update for |
| 51 | + /// that content is available; otherwise leaves the response untouched. |
| 52 | + /// </summary> |
| 53 | + /// <param name="contentRootRelativePath">The content root of the app's static assets relative to the |
| 54 | + /// app root, as passed to the <see cref="WebViewManager"/>.</param> |
| 55 | + /// <param name="requestAbsoluteUri">The absolute URI of the request being served.</param> |
| 56 | + /// <param name="responseStatusCode">The response status code. Set to <c>200</c> when content is replaced.</param> |
| 57 | + /// <param name="responseContent">The response content. Replaced with the hot-reloaded content, and the |
| 58 | + /// original stream is closed, when content is replaced.</param> |
| 59 | + /// <param name="responseHeaders">The response headers. The <c>Content-Type</c> header is updated when the |
| 60 | + /// hot reload payload specifies one.</param> |
| 61 | + /// <returns><see langword="true"/> if the response was replaced with hot-reloaded content; otherwise <see langword="false"/>.</returns> |
| 62 | + /// <exception cref="ArgumentNullException">Thrown if <paramref name="contentRootRelativePath"/>, |
| 63 | + /// <paramref name="requestAbsoluteUri"/>, <paramref name="responseContent"/> or |
| 64 | + /// <paramref name="responseHeaders"/> is <see langword="null"/>.</exception> |
| 65 | + public static bool TryReplaceResponseContent( |
| 66 | + string contentRootRelativePath, |
| 67 | + string requestAbsoluteUri, |
| 68 | + ref int responseStatusCode, |
| 69 | + ref Stream responseContent, |
| 70 | + IDictionary<string, string> responseHeaders) |
| 71 | + { |
| 72 | + ArgumentNullException.ThrowIfNull(contentRootRelativePath); |
| 73 | + ArgumentNullException.ThrowIfNull(requestAbsoluteUri); |
| 74 | + ArgumentNullException.ThrowIfNull(responseContent); |
| 75 | + ArgumentNullException.ThrowIfNull(responseHeaders); |
| 76 | + |
| 77 | + return StaticContentHotReloadManager.TryReplaceResponseContent( |
| 78 | + contentRootRelativePath, |
| 79 | + requestAbsoluteUri, |
| 80 | + ref responseStatusCode, |
| 81 | + ref responseContent, |
| 82 | + responseHeaders); |
| 83 | + } |
| 84 | + } |
| 85 | +} |
0 commit comments