diff --git a/Forte.Web.React/Configuration/ReactConfiguration.cs b/Forte.Web.React/Configuration/ReactConfiguration.cs index 9789015..e926592 100644 --- a/Forte.Web.React/Configuration/ReactConfiguration.cs +++ b/Forte.Web.React/Configuration/ReactConfiguration.cs @@ -26,6 +26,12 @@ public class ReactConfiguration /// public string NameOfObjectToSaveProps { get; set; } = "__reactProps"; + /// + /// Name of the object used to save global data object. Default value is "__globalData". + /// NameOfGlobalDataToSave is supported by method. + /// + public string NameOfGlobalDataToSave { get; set; } = "__globalData"; + /// /// Indicates whether caching is used. Default value is "true". /// diff --git a/Forte.Web.React/ForteWebReactExtensions.cs b/Forte.Web.React/ForteWebReactExtensions.cs index 0ef8ce1..2d4b0b8 100644 --- a/Forte.Web.React/ForteWebReactExtensions.cs +++ b/Forte.Web.React/ForteWebReactExtensions.cs @@ -48,7 +48,8 @@ public static void AddReact(this IServiceCollection services, } public static void UseReact(this IApplicationBuilder app, IEnumerable scriptUrls, Version reactVersion, - bool disableServerSideRendering = false, string? nameOfObjectToSaveProps = null, bool? useCache = null, bool? strictMode = null) + bool disableServerSideRendering = false, string? nameOfObjectToSaveProps = null, + string? nameOfGlobalDataToSave = null, bool? useCache = null, bool? strictMode = null) { var config = app.ApplicationServices.GetService(); @@ -61,6 +62,7 @@ public static void UseReact(this IApplicationBuilder app, IEnumerable sc config.ScriptUrls = scriptUrls.ToList(); config.ReactVersion = reactVersion; config.NameOfObjectToSaveProps = nameOfObjectToSaveProps ?? config.NameOfObjectToSaveProps; + config.NameOfGlobalDataToSave = nameOfGlobalDataToSave ?? config.NameOfGlobalDataToSave; config.UseCache = useCache ?? true; config.StrictMode = strictMode ?? false; } diff --git a/Forte.Web.React/HtmlHelperExtensions.cs b/Forte.Web.React/HtmlHelperExtensions.cs index 3883fd4..c78bca7 100644 --- a/Forte.Web.React/HtmlHelperExtensions.cs +++ b/Forte.Web.React/HtmlHelperExtensions.cs @@ -17,26 +17,34 @@ namespace Forte.Web.React; public static class HtmlHelperExtensions { #if NET48 - public static IHtmlString React(this HtmlHelper _, string componentName, T props) + public static IHtmlString React(this HtmlHelper _, string componentName, T props, object? globalData = null) { var reactService = DependencyResolver.Current.GetService(); - var renderedComponent = reactService.RenderToStringAsync(componentName, props).GetAwaiter().GetResult(); + var renderedComponent = reactService.RenderToStringAsync(componentName, props, globalData: globalData) + .GetAwaiter().GetResult(); return new HtmlString(renderedComponent); } - - public static IHtmlString React(this HtmlHelper _, TComponent component) where TComponent : IReactComponent + + public static IHtmlString React(this HtmlHelper _, TComponent component, object? globalData = null) + where TComponent : IReactComponent { var reactService = DependencyResolver.Current.GetService(); - var renderedComponent = reactService.RenderToStringAsync(component.Path, null, component.RenderingMode).GetAwaiter().GetResult(); + var renderedComponent = reactService + .RenderToStringAsync(component.Path, null, component.RenderingMode, globalData) + .GetAwaiter().GetResult(); return new HtmlString(renderedComponent); } - - public static IHtmlString React(this HtmlHelper _, TComponent component) where TComponent : IReactComponent where TProps : IReactComponentProps + + public static IHtmlString React(this HtmlHelper _, TComponent component, + object? globalData = null) + where TComponent : IReactComponent where TProps : IReactComponentProps { var reactService = DependencyResolver.Current.GetService(); - var renderedComponent = reactService.RenderToStringAsync(component.Path, component.Props, component.RenderingMode).GetAwaiter().GetResult(); + var renderedComponent = reactService + .RenderToStringAsync(component.Path, component.Props, component.RenderingMode, globalData).GetAwaiter() + .GetResult(); return new HtmlString(renderedComponent); } @@ -47,28 +55,38 @@ public static IHtmlString InitJavascript(this HtmlHelper _) return new HtmlString(reactService.GetInitJavascript()); } +} #endif #if NET6_0_OR_GREATER - public static async Task ReactAsync(this IHtmlHelper htmlHelper, string componentName, T props) + public static async Task ReactAsync(this IHtmlHelper htmlHelper, string componentName, T props, + object? globalData = null) { var reactService = htmlHelper.ViewContext.HttpContext.RequestServices.GetRequiredService(); - return new HtmlString(await reactService.RenderToStringAsync(componentName, props)); + return new HtmlString( + await reactService.RenderToStringAsync(componentName, props, globalData: globalData)); } - - public static async Task ReactAsync(this IHtmlHelper htmlHelper, TComponent component) where TComponent : IReactComponent + + public static async Task ReactAsync(this IHtmlHelper htmlHelper, TComponent component, + object? globalData = null) + where TComponent : IReactComponent { var reactService = htmlHelper.ViewContext.HttpContext.RequestServices.GetRequiredService(); - return new HtmlString(await reactService.RenderToStringAsync(component.Path, null, component.RenderingMode)); + return new HtmlString( + await reactService.RenderToStringAsync(component.Path, null, component.RenderingMode, globalData)); } - - public static async Task ReactAsync(this IHtmlHelper htmlHelper, TComponent component) where TComponent : IReactComponent where TProps : IReactComponentProps + + public static async Task ReactAsync(this IHtmlHelper htmlHelper, + TComponent component, object? globalData = + null) where TComponent : IReactComponent where TProps : IReactComponentProps { var reactService = htmlHelper.ViewContext.HttpContext.RequestServices.GetRequiredService(); - return new HtmlString(await reactService.RenderToStringAsync(component.Path, component.Props, component.RenderingMode)); + return new HtmlString( + await reactService.RenderToStringAsync(component.Path, component.Props, component.RenderingMode, + globalData)); } public static IHtmlContent InitJavascript(this IHtmlHelper htmlHelper) @@ -77,5 +95,5 @@ public static IHtmlContent InitJavascript(this IHtmlHelper htmlHelper) return new HtmlString(reactService.GetInitJavascript()); } -#endif } +#endif diff --git a/Forte.Web.React/React/ReactService.cs b/Forte.Web.React/React/ReactService.cs index d6a9c24..608a1fa 100644 --- a/Forte.Web.React/React/ReactService.cs +++ b/Forte.Web.React/React/ReactService.cs @@ -16,7 +16,9 @@ public interface IReactService Task> GetAvailableComponentNames(); Task RenderAsync(TextWriter writer, string componentName, object? props = null, RenderOptions? options = null); - Task RenderToStringAsync(string componentName, object? props = null, RenderingMode renderingMode = RenderingMode.ClientAndServer); + + Task RenderToStringAsync(string componentName, object? props = null, + RenderingMode renderingMode = RenderingMode.ClientAndServer, object? globalData = null); } public class ReactService : IReactService @@ -65,7 +67,7 @@ public ReactService(INodeJSService nodeJsService, IJsonSerializationService json } #endif - private async Task InvokeRenderTo(Component component, object? props = null, params object[] args) + private async Task InvokeRenderTo(Component component, object? props = null, object? globalData = null, params object[] args) { var allArgs = new List() { @@ -74,6 +76,8 @@ private async Task InvokeRenderTo(Component component, object? props = nul props, _config.ScriptUrls, _config.NameOfObjectToSaveProps, + _config.NameOfGlobalDataToSave, + globalData }; allArgs.AddRange(args); @@ -103,7 +107,8 @@ private async Task InvokeRenderTo(Component component, object? props = nul } - public async Task RenderToStringAsync(string componentName, object? props = null, RenderingMode renderingMode = RenderingMode.ClientAndServer) + public async Task RenderToStringAsync(string componentName, object? props = null, + RenderingMode renderingMode = RenderingMode.ClientAndServer, object? globalData = null) { var component = new Component(componentName, props, renderingMode); Components.Add(component); @@ -113,12 +118,13 @@ public async Task RenderToStringAsync(string componentName, object? prop return WrapRenderedStringComponent(string.Empty, component); } - var result = await InvokeRenderTo(component, props).ConfigureAwait(false); + var result = await InvokeRenderTo(component, props, globalData).ConfigureAwait(false); return WrapRenderedStringComponent(result, component); } - public async Task RenderAsync(TextWriter writer, string componentName, object? props = null, RenderOptions? options = null) + public async Task RenderAsync(TextWriter writer, string componentName, object? props = null, + RenderOptions? options = null) { options ??= new RenderOptions(); var component = new Component(componentName, props, options.RenderingMode); @@ -139,7 +145,8 @@ public async Task RenderAsync(TextWriter writer, string componentName, object? p IdentifierPrefix = _config.UseIdentifierPrefix ? component.ContainerId : null, }; - var result = await InvokeRenderTo(component, props, streamingOptions).ConfigureAwait(false); + var result = await InvokeRenderTo(component, props, streamingOptions) + .ConfigureAwait(false); using var reader = new StreamReader(await result.Content.ReadAsStreamAsync().ConfigureAwait(false)); @@ -161,7 +168,7 @@ public async Task> GetAvailableComponentNames() if (_config.UseCache) { var (success, cachedResult) = await _nodeJsService - .TryInvokeFromCacheAsync(getAvailableComponentNames, args: new [] { _config.ScriptUrls }) + .TryInvokeFromCacheAsync(getAvailableComponentNames, args: new[] { _config.ScriptUrls }) .ConfigureAwait(false); if (success) @@ -173,7 +180,7 @@ public async Task> GetAvailableComponentNames() using var stream = GetStreamFromEmbeddedScript(getAvailableComponentNames); var result = await _nodeJsService.InvokeFromStreamAsync(stream, - getAvailableComponentNames, args: new [] { _config.ScriptUrls }) + getAvailableComponentNames, args: new[] { _config.ScriptUrls }) .ConfigureAwait(false); return result!; @@ -185,7 +192,8 @@ private static Stream GetStreamFromEmbeddedScript(string scriptName) var manifestResourceName = $"Forte.Web.React.Scripts.{scriptName}"; var stream = currentAssembly.GetManifestResourceStream(manifestResourceName) ?? - throw new InvalidOperationException($"Could not get manifest resource with name - {manifestResourceName}"); + throw new InvalidOperationException( + $"Could not get manifest resource with name - {manifestResourceName}"); return stream; } @@ -219,7 +227,8 @@ private string GetInitJavascriptSource(Component c) private string CreateElement(Component component) { - var element = $"React.createElement(window.__react.{component.Path}, window.{_config.NameOfObjectToSaveProps}[\"{component.JsonContainerId}\"])"; + var element = + $"React.createElement(window.__react.{component.Path}, window.{_config.NameOfObjectToSaveProps}[\"{component.JsonContainerId}\"])"; return _config.StrictMode ? $"React.createElement(React.StrictMode, null, {element})" : element; } @@ -259,11 +268,12 @@ public class RenderOptions public RenderOptions() : this(RenderingMode.ClientAndServer, true) { } - - public RenderOptions(bool serverOnly, bool enableStreaming = true) : this(serverOnly ? RenderingMode.Server : RenderingMode.ClientAndServer, enableStreaming) + + public RenderOptions(bool serverOnly, bool enableStreaming = true) : this( + serverOnly ? RenderingMode.Server : RenderingMode.ClientAndServer, enableStreaming) { } - + public RenderOptions(RenderingMode renderingMode, bool enableStreaming = true) { RenderingMode = renderingMode; diff --git a/Forte.Web.React/Scripts/renderToString.js b/Forte.Web.React/Scripts/renderToString.js index b3b9ef0..f7086ce 100644 --- a/Forte.Web.React/Scripts/renderToString.js +++ b/Forte.Web.React/Scripts/renderToString.js @@ -4,7 +4,9 @@ jsonContainerId, props = {}, scriptFiles, - nameOfObjectToSaveProps + nameOfObjectToSaveProps, + nameOfGlobalDataToSave, + globalData = {} ) => { scriptFiles.forEach((scriptFile) => { require(scriptFile); @@ -13,6 +15,7 @@ const ReactDOMServer = global["ReactDOMServer"]; const React = global["React"]; const componentRepository = global["__react"] || {}; + global[nameOfGlobalDataToSave] = globalData; const path = componentName.split("."); let component = componentRepository[path[0]];