### Install Furion Package Source: https://github.com/monksoul/furion/blob/next/README.md Use this command to add the Furion package to your .NET project. ```powershell dotnet add package Furion ``` -------------------------------- ### Run Basic Furion Application Source: https://github.com/monksoul/furion/blob/next/README.md This C# code snippet demonstrates how to start a basic Furion application and define a dynamic API controller. Access the service via HTTP. ```csharp Serve.Run(); [DynamicApiController] public class HelloService { public string Say() => "Hello, Furion"; } ``` -------------------------------- ### Async/Await API Request Example Source: https://github.com/monksoul/furion/blob/next/clients/axios_vue_react/README.md Shows how to make an API request using the async/await syntax for cleaner asynchronous code. This pattern simplifies error handling and response processing. ```typescript const [err, res] = await feature(getAPI(SystemAPI).apiGetXXX()); if (err) { console.log(err); } else { var data = res.data.data!; } ``` -------------------------------- ### Promise API Request Example Source: https://github.com/monksoul/furion/blob/next/clients/axios_vue_react/README.md Demonstrates making an API request using the Promise-based approach. Ensure the API client and utility functions are correctly imported and configured. ```typescript getAPI(SystemAPI) .apiGetXXXX() .then((res) => { var data = res.data.data!; }) .catch((err) => { console.log(err); }) .finally(() => { console.log("api request completed."); }); ``` -------------------------------- ### Get All URI Query Variables Source: https://github.com/monksoul/furion/blob/next/framework/Furion/SpecificationDocument/Assets/index.html Retrieves all query parameters from a given URI or the current window's location. Returns an object where keys are parameter names and values are their corresponding values. ```javascript function getQueryVariables(uri) { var searchArgs = window.location.search; if (uri) { var s = uri.indexOf('?'); searchArgs = s > -1 ? uri.substring(s) : ''; } var query = searchArgs.substring(1); var vars = query.split('&'); var varObj = {}; for (var i = 0; i < vars.length; i++) { var pair = vars[i].split('='); varObj[pair[0]] = pair[1]; } return varObj; } ``` -------------------------------- ### Get Specific URI Query Variable Source: https://github.com/monksoul/furion/blob/next/framework/Furion/SpecificationDocument/Assets/index.html Fetches a specific query variable from a URI by its name. If the variable is not found, it returns false. ```javascript function getQueryVariable(variable, uri) { var vars = getQueryVariables(uri); for (var key in vars) { if (key === variable) return vars[key]; } return (false); } ``` -------------------------------- ### Initialize Swagger UI Source: https://github.com/monksoul/furion/blob/next/framework/Furion/SpecificationDocument/Assets/index.html Initializes the Swagger UI with provided configuration and OAuth objects. It includes custom interceptors and applies default settings. ```javascript function initSwaggerUI(configObject, oauthConfigObject) { configObject.onComplete = function () { var accessToken = window.localStorage.getItem(tokenKey); if (accessToken) { ui.preauthorizeApiKey("Bearer", accessToken); } appendLogoutButton(window.__swaggerLoginInfo); }; // Workaround for https://github.com/swagger-api/swagger-ui/issues/5945 configObject.urls.forEach(function (item) { if (item.url.startsWith("http") || item.url.startsWith("/")) return; item.url = window.location.href.replace("index.html", item.url).split('#')[0]; }); // If validatorUrl is not explicitly provided, disable the feature by setting to null if (!configObject.hasOwnProperty("validatorUrl")) configObject.validatorUrl = null // If oauth2RedirectUrl isn't specified, use the built-in default if (!configObject.hasOwnProperty("oauth2RedirectUrl")) configObject.oauth2RedirectUrl = (new URL("oauth2-redirect.html", window.location.href)).href; // Apply mandatory parameters configObject.dom_id = "#swagger-ui"; configObject.presets = [SwaggerUIBundle.presets.apis, SwaggerUIStandalonePreset, HideEmptyTagsPlugin]; configObject.layout = "StandaloneLayout"; // Parse and add interceptor functions var interceptors = JSON.parse('%(Interceptors)'); if (interceptors.RequestInterceptorFunction) configObject.requestInterceptor = parseFunction(interceptors.RequestInterceptorFunction); if (interceptors.ResponseInterceptorFunction) configObject.responseInterceptor = parseFunction(interceptors.ResponseInterceptorFunction); // Begin Swagger UI call region const ui = SwaggerUIBundle(configObject); ui.initOAuth(oauthConfigObject); // End Swagger UI call region window.ui = ui; } ``` -------------------------------- ### 新建特性分支 Source: https://github.com/monksoul/furion/blob/next/BRANCH_MANAGEMENT.md 从开发分支创建新的特性分支,用于开发新功能或改进。 ```git git checkout -b feature/your-feature develop ``` -------------------------------- ### Including Open Iconic Standalone Source: https://github.com/monksoul/furion/blob/next/templates/FurionBlazorTemplate/src/FurionBlazor.Web.Entry/wwwroot/css/open-iconic/README.md Link the default stylesheet for using Open Iconic without a specific framework. ```html ``` -------------------------------- ### Using Open Iconic with Foundation Classes Source: https://github.com/monksoul/furion/blob/next/templates/FurionBlazorTemplate/src/FurionBlazor.Web.Entry/wwwroot/css/open-iconic/README.md Apply Foundation icon classes to span elements for displaying icons. ```html ``` -------------------------------- ### Login and Initialization Logic Source: https://github.com/monksoul/furion/blob/next/framework/Furion/SpecificationDocument/Assets/index.html Handles user login submission, session management, and Swagger UI initialization. Includes error handling for invalid credentials and network issues. This code is typically used in a web application's authentication flow. ```javascript (res, headerMap) { if (res.toString() === "200") { loginForm.style.display = "none"; window.sessionStorage.setItem(loginSessionKey, "true"); initSwaggerUI(configObject, oauthConfigObject); } else { userName.focus(); submit.addEventListener("click", function (ev) { if (userName.value.trim().length === 0) { userName.focus(); return; } if (password.value.trim().length === 0) { password.focus(); return; } loginError.innerHTML = ""; sendRequest({ method: "POST", url: loginObject.SubmitUrl, data: { userName: userName.value.trim(), password: password.value.trim() }, success: function (res, headerMap) { if (res.toString() === "200") { loginForm.style.display = "none"; window.sessionStorage.setItem(loginSessionKey, "true"); initSwaggerUI(configObject, oauthConfigObject); defaultResponseInterceptor({ headers: headerMap }); } else { userName.focus(); loginError.innerHTML = "The account or password is invalid."; } }, error: function (xhr) { if (xhr.status === 404) { loginError.innerHTML = "Not Found: " + loginObject.SubmitUrl; } else { loginError.innerHTML = "Internal ServerError: " + loginObject.SubmitUrl; } } }); }); } else { initSwaggerUI(configObject, oauthConfigObject); } } ``` -------------------------------- ### Handle Page Load and Login Source: https://github.com/monksoul/furion/blob/next/framework/Furion/SpecificationDocument/Assets/index.html Handles the page load event, parsing configuration objects and managing the login process. It initializes Swagger UI or displays the login form. ```javascript window.onload = function () { var configObject = JSON.parse('%(ConfigObject)'); var oauthConfigObject = JSON.parse('%(OAuthConfigObject)'); window.__swaggerLoginInfo = configObject.LoginInfo; if (configObject.DarkMode === true) { document.documentElement.classList.add("dark-mode"); } if (window.sessionStorage.getItem(loginSessionKey) === "true") { initSwaggerUI(configObject, oauthConfigObject); return; } var loginObject = configObject.LoginInfo; if (loginObject && loginObject.Enabled === true) { var loginForm = document.getElementById("login-form"); var userName = document.getElementById("userName"); userName.value = loginObject.DefaultUsername; var password = document.getElementById("password"); password.value = loginObject.DefaultPassword; var submit = document.getElementById("submit"); var loginError = document.getElementById("login-error"); loginForm.style.display = "block"; sendRequest({ method: "POST", url: loginObject.CheckUrl, success: function ``` -------------------------------- ### Including Open Iconic with Foundation Source: https://github.com/monksoul/furion/blob/next/templates/FurionBlazorTemplate/src/FurionBlazor.Web.Entry/wwwroot/css/open-iconic/README.md Link the Foundation-specific stylesheet to use Open Iconic with Foundation framework classes. ```html ``` -------------------------------- ### Including Open Iconic with Bootstrap Source: https://github.com/monksoul/furion/blob/next/templates/FurionBlazorTemplate/src/FurionBlazor.Web.Entry/wwwroot/css/open-iconic/README.md Link the Bootstrap-specific stylesheet to use Open Iconic with Bootstrap framework classes. ```html ``` -------------------------------- ### Using Open Iconic with Bootstrap Classes Source: https://github.com/monksoul/furion/blob/next/templates/FurionBlazorTemplate/src/FurionBlazor.Web.Entry/wwwroot/css/open-iconic/README.md Apply Bootstrap icon classes to span elements for displaying icons. ```html ``` -------------------------------- ### Set Page Title Dynamically Source: https://github.com/monksoul/furion/blob/next/clients/schedule-dashboard/public/index.html Sets the document's title dynamically using a configuration object. Ensure the 'apiconfig' object is available in the global scope. ```javascript document.title = window.apiconfig.title; ``` -------------------------------- ### Using Open Iconic with Data Attributes Source: https://github.com/monksoul/furion/blob/next/templates/FurionBlazorTemplate/src/FurionBlazor.Web.Entry/wwwroot/css/open-iconic/README.md Apply Open Iconic classes and data-glyph attributes to span elements for displaying icons. ```html ``` -------------------------------- ### Swagger Multi-Group Configuration Source: https://github.com/monksoul/furion/blob/next/clients/axios_vue_react/README.md JSON configuration to enable the `EnableAllGroups` feature in Furion framework v3.3.4 and later, which merges all Swagger API groups into a single 'All Groups' endpoint. ```json { "SpecificationDocumentSettings": { "EnableAllGroups": true } } ``` -------------------------------- ### Sizing Icons with CSS Source: https://github.com/monksoul/furion/blob/next/templates/FurionBlazorTemplate/src/FurionBlazor.Web.Entry/wwwroot/css/open-iconic/README.md Apply basic CSS to the SVG container to control icon size. All icons are designed in a square format. ```css .icon { width: 16px; height: 16px; } ``` -------------------------------- ### Coloring Icons with CSS Source: https://github.com/monksoul/furion/blob/next/templates/FurionBlazorTemplate/src/FurionBlazor.Web.Entry/wwwroot/css/open-iconic/README.md Set the fill property on the specific icon's use tag to change its color. ```css .icon-account-login { fill: #f00; } ``` -------------------------------- ### TypeScript Compiler Options for Vue3 Source: https://github.com/monksoul/furion/blob/next/clients/axios_vue_react/README.md Configuration for `tsconfig.json` to resolve import issues in Vue3 projects with TypeScript and ESLint. These options are specifically for TypeScript 5.0 and later. ```json "compilerOptions": { "importsNotUsedAsValues": "remove", // TypeScript 5.0 - 使用 "preserveValueImports": false, // TypeScript 5.0 - 使用 // "verbatimModuleSyntax": false // TypeScript 5.0 + 使用 } ``` -------------------------------- ### Handle URL Query Parameters Source: https://github.com/monksoul/furion/blob/next/framework/Furion/SpecificationDocument/Assets/index.html Processes URL query parameters to update or remove them based on predefined keys and values. It also handles culture language settings. ```javascript function handleUrl(request) { var url = request.url; var temps = url.match(/\{[^\}]*\}/g); if (temps && temps.length > 0) { for (var i = 0; i < temps.length; i++) { var temp = temps[i]; var key = temp.substring(1, temp.length - 1); var queryKey = getQueryVariable(key, url); if (queryKey) { url = updateQueryVariable(url.replace(temp, queryKey), key); } else url = url.replace(temp, ''); } } request.url = url; } // handle culture lang var culture = getQueryVariable(cultureKey); if (culture && culture.length > 0) { request.url = updateQueryVariable(url, cultureKey, culture); } return request; } ``` -------------------------------- ### Displaying Open Iconic SVGs Source: https://github.com/monksoul/furion/blob/next/templates/FurionBlazorTemplate/src/FurionBlazor.Web.Entry/wwwroot/css/open-iconic/README.md Use this method to display individual SVG icons. Ensure the alt attribute is set for accessibility. ```html icon name ``` -------------------------------- ### Using Open Iconic SVG Sprite Source: https://github.com/monksoul/furion/blob/next/templates/FurionBlazorTemplate/src/FurionBlazor.Web.Entry/wwwroot/css/open-iconic/README.md Embed icons from an SVG sprite for efficient loading. Add a general class to the SVG and a unique class to the use tag for styling. ```html ``` -------------------------------- ### Format Code Snippets in Error Page Source: https://github.com/monksoul/furion/blob/next/framework/Furion/FriendlyException/Assets/error.html This JavaScript code iterates through elements with the class 'code' and formats their content into an ordered list with line numbers. It also handles HTML/XML escaping and displays the code language. ```javascript var codes = document.querySelectorAll(".code"); Array.prototype.forEach.call(codes, function (code, i) { var language = code.getAttribute("data-language"); var html = code.innerHTML; if ( language.toLowerCase() == "html" || language.toLowerCase() == "xml" ) { html = html .replace(/&(?!#?[\[a-zA-Z0-9\]]+;)/g, "&") .replace(//g, ">") .replace(/'/g, "'") .replace(/"/g, """); } code.innerHTML = '
  1. ' + html.replace(/[ ]+/g, "
  2. ") + '
' + language + ""; }); ``` -------------------------------- ### Swagger Plugin: Hide Empty Tags Source: https://github.com/monksoul/furion/blob/next/framework/Furion/SpecificationDocument/Assets/index.html A Swagger UI plugin that filters out API tags that have no associated operations. This helps in cleaning up the UI by hiding unused sections. ```javascript var HideEmptyTagsPlugin = function HideEmptyTagsPlugin() { return { statePlugins: { spec: { wrapSelectors: { taggedOperations: function taggedOperations(ori) { return function () { return ori.apply(void 0, arguments).filter(function (tagMeta) { return tagMeta.get("operations") && tagMeta.get("operations").size > 0; }); }; } } } } }; }; ``` -------------------------------- ### Append Logout Button to UI Source: https://github.com/monksoul/furion/blob/next/framework/Furion/SpecificationDocument/Assets/index.html Appends a logout button to the top bar of the UI if login is enabled. It uses a session key for logout functionality. ```javascript function appendLogoutButton(loginObject) { if (!loginObject || loginObject.Enabled !== true) return; var topbarWrapper = document.querySelector('.topbar-wrapper'); if (!topbarWrapper) { setTimeout(function() { appendLogoutButton(loginObject); }, 200); return; } if (document.getElementById('swagger-logout-btn')) return; var btn = document.createElement('button'); btn.id = 'swagger-logout-btn'; btn.className = 'swagger-logout-btn'; btn.innerHTML = '⏻'; btn.addEventListener('click', function(e) { e.preventDefault(); window.sessionStorage.removeItem(loginSessionKey); window.location.reload(); }); topbarWrapper.appendChild(btn); } ``` -------------------------------- ### Update or Add URI Query Variable Source: https://github.com/monksoul/furion/blob/next/framework/Furion/SpecificationDocument/Assets/index.html Updates an existing query variable in a URI or adds it if it doesn't exist. If the value is null or undefined, the variable is removed. Handles both adding and updating query parameters. ```javascript function updateQueryVariable(uri, key, value) { var re = new RegExp('([?&])' + key + '=.*?(&|$)', 'i'); var separator = uri.indexOf('?') !== -1 ? '&' : '?'; if (uri.match(re)) { return uri.replace(re, !value ? '' : ('$1' + key + '=' + value + '$2')); } else { return !value ? '' : (uri + separator + key + '=' + value); } } ``` -------------------------------- ### Send AJAX Request Source: https://github.com/monksoul/furion/blob/next/framework/Furion/SpecificationDocument/Assets/index.html Sends an AJAX request using XMLHttpRequest. Handles success and error callbacks, parses JSON responses, and extracts headers. ```javascript function sendRequest(params) { let xhr = new XMLHttpRequest(); xhr.onreadystatechange = function () { if (xhr.readyState == 4 && xhr.status == 200) { let obj = JSON.parse(xhr.response); let headers = xhr.getAllResponseHeaders(); let arr = headers.trim().split(/[ ]+/); let headerMap = {}; arr.forEach(function (line) { let parts = line.split(': '); let header = parts.shift(); let value = parts.join(': '); headerMap[header] = value; }); params.success(obj, headerMap); } else if (xhr.readyState == 4 && xhr.status >= 400) { params.error(xhr); } } function objectToString(obj) { let arr = []; for (var k in obj) { arr.push(`${k}=${encodeURIComponent(obj[k])}`); } return arr.join('&'); } let qs = objectToString(params.data); var accessToken = window.localStorage.getItem(tokenKey); if (params.method.toUpperCase() == 'GET') { xhr.open('GET', params.url + '?' + qs); if (accessToken) { xhr.setRequestHeader('Authorization', 'Bearer ' + accessToken); } xhr.send(); } else if (params.method.toUpperCase() == 'POST') { xhr.open('POST', params.url); if (accessToken) { xhr.setRequestHeader('Authorization', 'Bearer ' + accessToken); } xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); xhr.send(qs); } } ``` -------------------------------- ### Extract URI Template Variables Source: https://github.com/monksoul/furion/blob/next/framework/Furion/SpecificationDocument/Assets/index.html Extracts template variables from a URI string. Template variables are typically enclosed in curly braces. ```javascript function getUrlTemplate(uri) { var reg = /\{(.+?)\}/g; return uri.match(reg); } ``` -------------------------------- ### Parse Function String to Object Source: https://github.com/monksoul/furion/blob/next/framework/Furion/SpecificationDocument/Assets/index.html Parses a string representation of a JavaScript function into an actual function object without using eval. Useful for dynamic function creation from string definitions. ```javascript function parseFunction(str) { if (!str) return void (0); var fn_body_idx = str.indexOf('{'), fn_body = str.substring(fn_body_idx + 1, str.lastIndexOf('}')), fn_declare = str.substring(0, fn_body_idx), fn_params = fn_declare.substring(fn_declare.indexOf('(') + 1, fn_declare.lastIndexOf(')')), args = fn_params.split(','); args.push(fn_body); function Fn() { return Function.apply(this, args); } Fn.prototype = Function.prototype; return new Fn(); } ``` -------------------------------- ### Default API Request Interceptor Source: https://github.com/monksoul/furion/blob/next/framework/Furion/SpecificationDocument/Assets/index.html Adds a 'request-from' header to outgoing API requests and handles URL template replacements. It's designed to augment requests before they are sent. ```javascript // default request interceptor function defaultRequestInterceptor(request) { var url = request.url; // add swagger header request.headers["request-from"] = "swagger"; // handle template var temps = getUrlTemplate(url); if (temps && temps.length > 0) { for (var i = 0; i < temps.length; i++) { // Placeholder for actual template variable replacement logic } } return request; } ``` -------------------------------- ### Default API Response Interceptor Source: https://github.com/monksoul/furion/blob/next/framework/Furion/SpecificationDocument/Assets/index.html Handles JWT token management and UI authorization updates based on API responses. It stores valid tokens and logs out the user if the token is invalid. ```javascript var tokenKey = "access-token"; var cultureKey = "culture"; var loginSessionKey = "swagger-logged-in"; // default response interceptor function defaultResponseInterceptor(response) { // handle jwt token var accessToken = response.headers[tokenKey]; if (accessToken && accessToken != "invalid_token") { window.localStorage.setItem(tokenKey, accessToken); ui.preauthorizeApiKey("Bearer", accessToken); } else if (accessToken == "invalid_token") { window.localStorage.removeItem(tokenKey); ui.authActions.logout(["Bearer"]); } return response; } ``` -------------------------------- ### Angular RequiredError Override Source: https://github.com/monksoul/furion/blob/next/clients/axios_vue_react/README.md Adds the `override` keyword to the `RequiredError` class in `api-services/base.ts` to resolve potential errors in Angular projects. ```typescript export class RequiredError extends Error { override name: "RequiredError" = "RequiredError"; } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.