{"id":299,"date":"2025-09-29T17:36:05","date_gmt":"2025-09-29T21:36:05","guid":{"rendered":"http:\/\/wordpress.home.internal\/?p=299"},"modified":"2025-10-01T16:16:59","modified_gmt":"2025-10-01T16:16:59","slug":"blazor-server-via-php","status":"publish","type":"post","link":"https:\/\/lcigaming.ca\/articles\/blazor-server-via-php\/","title":{"rendered":"Blazor Server via PHP"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\">Introduction<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">In <a href=\"https:\/\/lcigaming.ca\/articles\/using-php-with-blazor\/\" title=\"\">Using PHP with Blazor<\/a> I showed how to use PHP on the server to support a Blazor Web Standalone application. In this post I will show how to run a client-server Blazor Web App with PHP acting as a bridge. This approach minimizes the PHP logic necessary for supporting Blazor apps on a server where you do not have administrator rights.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Environment<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">My server environment has not changed since my previous posts:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Ubuntu 22.04.1 (LTS)<\/li>\n\n\n\n<li>Apache 2.4.52 (Ubuntu)<\/li>\n\n\n\n<li>PHP 8.1.2-1ubuntu2.22<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">The version of dotnet installed on the server is not relevant as we will not be using it for this exercise.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Source Code<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The source code for this post is available on <a href=\"https:\/\/github.com\/BarryALay\/blog1001-source\" title=\"\">GitHub<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Client-Server Using Blazor<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Our app this time will be built on top of the Blazor Web App template:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Project name: PHPBridge<\/li>\n\n\n\n<li>Authentication type: None<\/li>\n\n\n\n<li>Interactive render mode: WebAssembly<\/li>\n\n\n\n<li>Interactivity location: Global<\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" src=\"https:\/\/lcigaming.ca\/articles\/wp-content\/uploads\/2025\/09\/Blazor-Web-App-WebAssembly-Global.png\" alt=\"\" class=\"wp-image-301\"\/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">As always, modify the app to work on our server:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Remove the <em>base <\/em>element in <em>wwwroot\\index.html<\/em>.<\/li>\n\n\n\n<li>Add <code>@page \"\/home\"<\/code> to <em>Pages\\Home.razor<\/em>.<\/li>\n\n\n\n<li>Modify the first <em>NavLink <\/em>element in <em>Layout\\NavMenu.razor<\/em> to use <code>href=\"home\"<\/code>.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">We will work in the development environment for now. I will demonstrate how to deploy and run the app on Linux a bit later on.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This demonstration will build on the Weather and Counter pages from the template, serving data from the server to the client using a simple web API.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Shared Data<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">We will use a shared project to hold common structures and data.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Create a new project called <em>PHPBridge.Shared<\/em> within the <em>PHPBridge <\/em>solution.  This project does not need to be a Blazor project at all &#8211; a simple class library project will do.  I navigated to the <em>PHPBridge <\/em>folder within the solution in order to put all of the sub-projects at the same level:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" src=\"https:\/\/lcigaming.ca\/articles\/wp-content\/uploads\/2025\/09\/Shared-sub-project.png\" alt=\"\" class=\"wp-image-303\"\/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Add a <em>Model <\/em>directory to the new project. Within it, add <em>WeatherForecast.cs<\/em>:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:clamp(14px, .875rem, 21px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#f2f2f2;color:#2f363c\">C#<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#24292e;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>namespace PHPBridge.Shared.Model\n{\n    public class WeatherForecast\n    {\n        public DateOnly Date { get; set; }\n\n        public int TemperatureC { get; set; }\n\n        public string? Summary { get; set; }\n\n        public int TemperatureF => 32 + (int)(TemperatureC \/ 0.5556);\n    }\n}<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki github-light\" style=\"background-color: #fff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #D73A49\">namespace<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">PHPBridge<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Shared<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Model<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">class<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">WeatherForecast<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">DateOnly<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Date<\/span><span style=\"color: #24292E\"> { <\/span><span style=\"color: #D73A49\">get<\/span><span style=\"color: #24292E\">; <\/span><span style=\"color: #D73A49\">set<\/span><span style=\"color: #24292E\">; }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">int<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">TemperatureC<\/span><span style=\"color: #24292E\"> { <\/span><span style=\"color: #D73A49\">get<\/span><span style=\"color: #24292E\">; <\/span><span style=\"color: #D73A49\">set<\/span><span style=\"color: #24292E\">; }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\">? <\/span><span style=\"color: #6F42C1\">Summary<\/span><span style=\"color: #24292E\"> { <\/span><span style=\"color: #D73A49\">get<\/span><span style=\"color: #24292E\">; <\/span><span style=\"color: #D73A49\">set<\/span><span style=\"color: #24292E\">; }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">int<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">TemperatureF<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">32<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">+<\/span><span style=\"color: #24292E\"> (<\/span><span style=\"color: #D73A49\">int<\/span><span style=\"color: #24292E\">)(TemperatureC <\/span><span style=\"color: #D73A49\">\/<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">0.5556<\/span><span style=\"color: #24292E\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">This should look familiar. Add <em>Model\\CounterData.cs<\/em>:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:clamp(14px, .875rem, 21px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#f2f2f2;color:#2f363c\">C#<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#24292e;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>namespace PHPBridge.Shared.Model\n{\n    public class CounterData\n    {\n        public int Count { get; set; }\n        public string? Action { get; set; }\n    }\n}<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki github-light\" style=\"background-color: #fff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #D73A49\">namespace<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">PHPBridge<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Shared<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Model<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">class<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">CounterData<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">int<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Count<\/span><span style=\"color: #24292E\"> { <\/span><span style=\"color: #D73A49\">get<\/span><span style=\"color: #24292E\">; <\/span><span style=\"color: #D73A49\">set<\/span><span style=\"color: #24292E\">; }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\">? <\/span><span style=\"color: #6F42C1\">Action<\/span><span style=\"color: #24292E\"> { <\/span><span style=\"color: #D73A49\">get<\/span><span style=\"color: #24292E\">; <\/span><span style=\"color: #D73A49\">set<\/span><span style=\"color: #24292E\">; }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Now add <em>Model\\APIConstants.cs<\/em>:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:clamp(14px, .875rem, 21px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#f2f2f2;color:#2f363c\">C#<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#24292e;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>namespace PHPBridge.Shared.Model\n{\n    public class APIConstants\n    {\n        public const string BOUNDARY = \"boundary\";\n\n        public const string WEATHER = \"weather\";\n        \n        public const string COUNTER = \"counter\";\n        public const string INCREMENT = \"increment\";\n        public const string DECREMENT = \"decrement\";\n    }\n}<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki github-light\" style=\"background-color: #fff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #D73A49\">namespace<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">PHPBridge<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Shared<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Model<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">class<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">APIConstants<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">const<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">BOUNDARY<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">&quot;boundary&quot;<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">const<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">WEATHER<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">&quot;weather&quot;<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">const<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">COUNTER<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">&quot;counter&quot;<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">const<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">INCREMENT<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">&quot;increment&quot;<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">const<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">DECREMENT<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">&quot;decrement&quot;<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">This last class provides constants that will be used on both the client and server side of the API.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">The Server<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The server side logic for our application is in the main project <em>PHPBridge<\/em>. We will need to add some more logic to the component to support client requests for data.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">First, create a project reference to <em>PHPBridge.Shared<\/em>:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" src=\"https:\/\/lcigaming.ca\/articles\/wp-content\/uploads\/2025\/09\/Shared-project-reference.png\" alt=\"\" class=\"wp-image-310\"\/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Next, create new folder <em>Engine<\/em>, and create <em>ServerState.cs<\/em> within it:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:clamp(14px, .875rem, 21px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#f2f2f2;color:#2f363c\">C#<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#24292e;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>namespace PHPBridge.Engine\n{\n    internal class ServerState\n    {\n        private int counter = 0;\n        public int Counter\n        {\n            get => counter; \n            set => counter = value;\n        }\n\n        public int IncrementCounter() => ++counter;\n        public int DecrementCounter() => --counter;\n    }\n}<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki github-light\" style=\"background-color: #fff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #D73A49\">namespace<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">PHPBridge<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Engine<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">internal<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">class<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">ServerState<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">private<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">int<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">counter<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">0<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">int<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Counter<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">get<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> counter; <\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">set<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> counter <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> value;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">int<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">IncrementCounter<\/span><span style=\"color: #24292E\">() <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">++<\/span><span style=\"color: #24292E\">counter;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">int<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">DecrementCounter<\/span><span style=\"color: #24292E\">() <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">--<\/span><span style=\"color: #24292E\">counter;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">This will hold the persisted value of the counter across requests, somewhat like how <em>boundary.php<\/em> in the previous post used the PHP Session to do this.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Create <em>Engine\\API.cs<\/em>:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:clamp(14px, .875rem, 21px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#f2f2f2;color:#2f363c\">C#<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#24292e;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>using PHPBridge.Shared.Model;\n\nnamespace PHPBridge.Engine\n{\n    internal static class API\n    {\n        public static WebApplication MapAPI(this WebApplication app)\n        {\n            var endPoints = app.MapGroup($\"\/{APIConstants.BOUNDARY}\");\n\n            endPoints.MapGet(\n                $\"\/{APIConstants.WEATHER}\", \n                ()  => GetWeatherForecasts());\n            endPoints.MapGet(\n                $\"\/{APIConstants.COUNTER}\", \n                (ServerState state) => GetCounterData(state));\n            endPoints.MapPost(\n                $\"\/{APIConstants.COUNTER}\/{APIConstants.INCREMENT}\", \n                (ServerState state) => IncrementCounter(state));\n            endPoints.MapPost(\n                $\"\/{APIConstants.COUNTER}\/{APIConstants.DECREMENT}\", \n                (ServerState state) => DecrementCounter(state));\n\n            return app;\n        }\n\n        private static WeatherForecast[] GetWeatherForecasts()\n        {\n            return\n            &#91;\n                new WeatherForecast { \n                    Date = new DateOnly(2022, 1, 6), \n                    TemperatureC = 1, \n                    Summary = \"Freezing\" },\n                new WeatherForecast { \n                    Date = new DateOnly(2022, 1, 7), \n                    TemperatureC = 14, \n                    Summary = \"Bracing\" },\n                new WeatherForecast { \n                    Date = new DateOnly(2022, 1, 8), \n                    TemperatureC = -13, \n                    Summary = \"Freezing\" },\n                new WeatherForecast { \n                    Date = new DateOnly(2022, 1, 9), \n                    TemperatureC = -16, \n                    Summary = \"Balmy\" },\n                new WeatherForecast { \n                    Date = new DateOnly(2022, 1, 10), \n                    TemperatureC = -2, \n                    Summary = \"Chilly\" },\n            &#93;;\n        }\n\n        private static CounterData GetCounterData(ServerState state)\n        {\n            return new CounterData { \n                Action = \"none\", \n                Count = state.Counter };\n        }\n\n        private static CounterData IncrementCounter(ServerState state)\n        {\n            return new CounterData { \n                Action = \"increment\", \n                Count = state.IncrementCounter() };\n        }\n\n        private static CounterData DecrementCounter(ServerState state)\n        {\n            return new CounterData { \n                Action = \"decrement\", \n                Count = state.DecrementCounter() };\n        }\n    }\n}\n<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki github-light\" style=\"background-color: #fff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #D73A49\">using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">PHPBridge<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Shared<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Model<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">namespace<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">PHPBridge<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Engine<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">internal<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">static<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">class<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">API<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">static<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">WebApplication<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">MapAPI<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #D73A49\">this<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">WebApplication<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">app<\/span><span style=\"color: #24292E\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">var<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">endPoints<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> app.<\/span><span style=\"color: #6F42C1\">MapGroup<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #032F62\">$&quot;\/{<\/span><span style=\"color: #24292E\">APIConstants<\/span><span style=\"color: #032F62\">.<\/span><span style=\"color: #24292E\">BOUNDARY<\/span><span style=\"color: #032F62\">}&quot;<\/span><span style=\"color: #24292E\">);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            endPoints.<\/span><span style=\"color: #6F42C1\">MapGet<\/span><span style=\"color: #24292E\">(<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #032F62\">$&quot;\/{<\/span><span style=\"color: #24292E\">APIConstants<\/span><span style=\"color: #032F62\">.<\/span><span style=\"color: #24292E\">WEATHER<\/span><span style=\"color: #032F62\">}&quot;<\/span><span style=\"color: #24292E\">, <\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                ()  <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">GetWeatherForecasts<\/span><span style=\"color: #24292E\">());<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            endPoints.<\/span><span style=\"color: #6F42C1\">MapGet<\/span><span style=\"color: #24292E\">(<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #032F62\">$&quot;\/{<\/span><span style=\"color: #24292E\">APIConstants<\/span><span style=\"color: #032F62\">.<\/span><span style=\"color: #24292E\">COUNTER<\/span><span style=\"color: #032F62\">}&quot;<\/span><span style=\"color: #24292E\">, <\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                (<\/span><span style=\"color: #6F42C1\">ServerState<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">state<\/span><span style=\"color: #24292E\">) <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">GetCounterData<\/span><span style=\"color: #24292E\">(state));<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            endPoints.<\/span><span style=\"color: #6F42C1\">MapPost<\/span><span style=\"color: #24292E\">(<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #032F62\">$&quot;\/{<\/span><span style=\"color: #24292E\">APIConstants<\/span><span style=\"color: #032F62\">.<\/span><span style=\"color: #24292E\">COUNTER<\/span><span style=\"color: #032F62\">}\/{<\/span><span style=\"color: #24292E\">APIConstants<\/span><span style=\"color: #032F62\">.<\/span><span style=\"color: #24292E\">INCREMENT<\/span><span style=\"color: #032F62\">}&quot;<\/span><span style=\"color: #24292E\">, <\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                (<\/span><span style=\"color: #6F42C1\">ServerState<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">state<\/span><span style=\"color: #24292E\">) <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">IncrementCounter<\/span><span style=\"color: #24292E\">(state));<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            endPoints.<\/span><span style=\"color: #6F42C1\">MapPost<\/span><span style=\"color: #24292E\">(<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #032F62\">$&quot;\/{<\/span><span style=\"color: #24292E\">APIConstants<\/span><span style=\"color: #032F62\">.<\/span><span style=\"color: #24292E\">COUNTER<\/span><span style=\"color: #032F62\">}\/{<\/span><span style=\"color: #24292E\">APIConstants<\/span><span style=\"color: #032F62\">.<\/span><span style=\"color: #24292E\">DECREMENT<\/span><span style=\"color: #032F62\">}&quot;<\/span><span style=\"color: #24292E\">, <\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                (<\/span><span style=\"color: #6F42C1\">ServerState<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">state<\/span><span style=\"color: #24292E\">) <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">DecrementCounter<\/span><span style=\"color: #24292E\">(state));<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">return<\/span><span style=\"color: #24292E\"> app;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">private<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">static<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">WeatherForecast<\/span><span style=\"color: #24292E\">[] <\/span><span style=\"color: #6F42C1\">GetWeatherForecasts<\/span><span style=\"color: #24292E\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">return<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            &#91;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">WeatherForecast<\/span><span style=\"color: #24292E\"> { <\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    Date <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">DateOnly<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #005CC5\">2022<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #005CC5\">1<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #005CC5\">6<\/span><span style=\"color: #24292E\">), <\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    TemperatureC <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">1<\/span><span style=\"color: #24292E\">, <\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    Summary <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">&quot;Freezing&quot;<\/span><span style=\"color: #24292E\"> },<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">WeatherForecast<\/span><span style=\"color: #24292E\"> { <\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    Date <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">DateOnly<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #005CC5\">2022<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #005CC5\">1<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #005CC5\">7<\/span><span style=\"color: #24292E\">), <\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    TemperatureC <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">14<\/span><span style=\"color: #24292E\">, <\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    Summary <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">&quot;Bracing&quot;<\/span><span style=\"color: #24292E\"> },<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">WeatherForecast<\/span><span style=\"color: #24292E\"> { <\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    Date <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">DateOnly<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #005CC5\">2022<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #005CC5\">1<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #005CC5\">8<\/span><span style=\"color: #24292E\">), <\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    TemperatureC <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">-<\/span><span style=\"color: #005CC5\">13<\/span><span style=\"color: #24292E\">, <\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    Summary <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">&quot;Freezing&quot;<\/span><span style=\"color: #24292E\"> },<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">WeatherForecast<\/span><span style=\"color: #24292E\"> { <\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    Date <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">DateOnly<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #005CC5\">2022<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #005CC5\">1<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #005CC5\">9<\/span><span style=\"color: #24292E\">), <\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    TemperatureC <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">-<\/span><span style=\"color: #005CC5\">16<\/span><span style=\"color: #24292E\">, <\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    Summary <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">&quot;Balmy&quot;<\/span><span style=\"color: #24292E\"> },<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">WeatherForecast<\/span><span style=\"color: #24292E\"> { <\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    Date <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">DateOnly<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #005CC5\">2022<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #005CC5\">1<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #005CC5\">10<\/span><span style=\"color: #24292E\">), <\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    TemperatureC <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">-<\/span><span style=\"color: #005CC5\">2<\/span><span style=\"color: #24292E\">, <\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    Summary <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">&quot;Chilly&quot;<\/span><span style=\"color: #24292E\"> },<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            &#93;;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">private<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">static<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">CounterData<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">GetCounterData<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #6F42C1\">ServerState<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">state<\/span><span style=\"color: #24292E\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">return<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">CounterData<\/span><span style=\"color: #24292E\"> { <\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                Action <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">&quot;none&quot;<\/span><span style=\"color: #24292E\">, <\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                Count <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> state.Counter };<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">private<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">static<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">CounterData<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">IncrementCounter<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #6F42C1\">ServerState<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">state<\/span><span style=\"color: #24292E\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">return<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">CounterData<\/span><span style=\"color: #24292E\"> { <\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                Action <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">&quot;increment&quot;<\/span><span style=\"color: #24292E\">, <\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                Count <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> state.<\/span><span style=\"color: #6F42C1\">IncrementCounter<\/span><span style=\"color: #24292E\">() };<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">private<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">static<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">CounterData<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">DecrementCounter<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #6F42C1\">ServerState<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">state<\/span><span style=\"color: #24292E\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">return<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">CounterData<\/span><span style=\"color: #24292E\"> { <\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                Action <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">&quot;decrement&quot;<\/span><span style=\"color: #24292E\">, <\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                Count <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> state.<\/span><span style=\"color: #6F42C1\">DecrementCounter<\/span><span style=\"color: #24292E\">() };<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">}<\/span><\/span>\n<span class=\"line\"><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Register the API in <em>Program.cs<\/em> in the main <em>PHPBridge<\/em> project:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:clamp(14px, .875rem, 21px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-highlight-color:rgba(16, 41, 67, 0.2);line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#f2f2f2;color:#2f363c\">C#<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#24292e;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>using PHPBridge.Components;\nusing PHPBridge.Engine;\n\nnamespace BlazorSecurityDemo\n{\n    public class Program\n    {\n        public static void Main(string[] args)\n        {\n            var builder = WebApplication.CreateBuilder(args);\n\n            \/\/ Add services to the container.\n            builder.Services.AddRazorComponents()\n                .AddInteractiveServerComponents();\n\n            builder.Services.AddSingleton&lt;ServerState>();\n            \n            var app = builder.Build();\n\n            \/\/ Configure the HTTP request pipeline.\n            if (!app.Environment.IsDevelopment())\n            {\n                app.UseExceptionHandler(\"\/Error\");\n                \/\/ The default HSTS value is 30 days...\n                app.UseHsts();\n            }\n\n            app.UseHttpsRedirection();\n\n            app.UseAntiforgery();\n\n            app.MapStaticAssets();\n            app.MapRazorComponents&lt;App>()\n                .AddInteractiveServerRenderMode();\n\n            app.MapApi();\n            \n            app.Run();\n        }\n    }\n}\n<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki github-light\" style=\"background-color: #fff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #D73A49\">using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">PHPBridge<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Components<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">PHPBridge<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Engine<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">namespace<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">BlazorSecurityDemo<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">class<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Program<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">static<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">void<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Main<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\">[] <\/span><span style=\"color: #6F42C1\">args<\/span><span style=\"color: #24292E\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">var<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">builder<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> WebApplication.<\/span><span style=\"color: #6F42C1\">CreateBuilder<\/span><span style=\"color: #24292E\">(args);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #6A737D\">            \/\/ Add services to the container.<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            builder.Services.<\/span><span style=\"color: #6F42C1\">AddRazorComponents<\/span><span style=\"color: #24292E\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                .<\/span><span style=\"color: #6F42C1\">AddInteractiveServerComponents<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">            builder.Services.<\/span><span style=\"color: #6F42C1\">AddSingleton<\/span><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #6F42C1\">ServerState<\/span><span style=\"color: #24292E\">&gt;();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">var<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">app<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> builder.<\/span><span style=\"color: #6F42C1\">Build<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #6A737D\">            \/\/ Configure the HTTP request pipeline.<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">if<\/span><span style=\"color: #24292E\"> (<\/span><span style=\"color: #D73A49\">!<\/span><span style=\"color: #24292E\">app.Environment.<\/span><span style=\"color: #6F42C1\">IsDevelopment<\/span><span style=\"color: #24292E\">())<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                app.<\/span><span style=\"color: #6F42C1\">UseExceptionHandler<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #032F62\">&quot;\/Error&quot;<\/span><span style=\"color: #24292E\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6A737D\">                \/\/ The default HSTS value is 30 days...<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                app.<\/span><span style=\"color: #6F42C1\">UseHsts<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            app.<\/span><span style=\"color: #6F42C1\">UseHttpsRedirection<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            app.<\/span><span style=\"color: #6F42C1\">UseAntiforgery<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            app.<\/span><span style=\"color: #6F42C1\">MapStaticAssets<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            app.<\/span><span style=\"color: #6F42C1\">MapRazorComponents<\/span><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #6F42C1\">App<\/span><span style=\"color: #24292E\">&gt;()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                .<\/span><span style=\"color: #6F42C1\">AddInteractiveServerRenderMode<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">            app.<\/span><span style=\"color: #6F42C1\">MapApi<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            app.<\/span><span style=\"color: #6F42C1\">Run<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">}<\/span><\/span>\n<span class=\"line\"><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">The <em>MapAPI <\/em>method registers a set of endpoints that respond to various client requests:<\/p>\n\n\n\n<dl class=\"wp-block-description-list-block-description-list\"><dt style=\"--termsMarginTop:0px;--termsMarginBottom:0px;--termsMarginLeft:0px;--termsMarginRight:0px;--termsPaddingTop:0px;--termsPaddingBottom:false;--termsPaddingLeft:0px;--termsPaddingRight:0px\"><strong>GET \/boundary\/weather<\/strong><\/dt><dd style=\"--descriptionsMarginTop:0px;--descriptionsMarginBottom:0px;--descriptionsMarginLeft:0px;--descriptionsMarginRight:0px;--descriptionsMarginInlineStart:10%;--descriptionsPaddingTop:0px;--descriptionsPaddingBottom:0px;--descriptionsPaddingLeft:0px;--descriptionsPaddingRight:0px\">Retrieve weather data.<\/dd><dt style=\"--termsMarginTop:0px;--termsMarginBottom:0px;--termsMarginLeft:0px;--termsMarginRight:0px;--termsPaddingTop:0px;--termsPaddingBottom:false;--termsPaddingLeft:0px;--termsPaddingRight:0px\"><strong>GET \/boundary\/counter<\/strong><\/dt><dd style=\"--descriptionsMarginTop:0px;--descriptionsMarginBottom:0px;--descriptionsMarginLeft:0px;--descriptionsMarginRight:0px;--descriptionsMarginInlineStart:10%;--descriptionsPaddingTop:0px;--descriptionsPaddingBottom:0px;--descriptionsPaddingLeft:0px;--descriptionsPaddingRight:0px\">Retrieve the current counter value.<\/dd><dt style=\"--termsMarginTop:0px;--termsMarginBottom:0px;--termsMarginLeft:0px;--termsMarginRight:0px;--termsPaddingTop:0px;--termsPaddingBottom:false;--termsPaddingLeft:0px;--termsPaddingRight:0px\"><strong>POST \/boundary\/counter\/increment<\/strong><\/dt><dd style=\"--descriptionsMarginTop:0px;--descriptionsMarginBottom:0px;--descriptionsMarginLeft:0px;--descriptionsMarginRight:0px;--descriptionsMarginInlineStart:10%;--descriptionsPaddingTop:0px;--descriptionsPaddingBottom:0px;--descriptionsPaddingLeft:0px;--descriptionsPaddingRight:0px\">Increment the counter and return the new value.<\/dd><dt style=\"--termsMarginTop:0px;--termsMarginBottom:0px;--termsMarginLeft:0px;--termsMarginRight:0px;--termsPaddingTop:0px;--termsPaddingBottom:false;--termsPaddingLeft:0px;--termsPaddingRight:0px\"><strong>POST \/boundary\/counter\/decrement<\/strong><\/dt><dd style=\"--descriptionsMarginTop:0px;--descriptionsMarginBottom:0px;--descriptionsMarginLeft:0px;--descriptionsMarginRight:0px;--descriptionsMarginInlineStart:10%;--descriptionsPaddingTop:0px;--descriptionsPaddingBottom:0px;--descriptionsPaddingLeft:0px;--descriptionsPaddingRight:0px\">Decrement the counter and return the new value.<\/dd><\/dl>\n\n\n\n<p class=\"wp-block-paragraph\">For the <em>counter<\/em>-oriented mappings the delegates reference the registered singleton <em>ServerState <\/em>to provide access to the persistent counter.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">The Client<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The client side logic is in the project <em>PHPBridge.Client<\/em>.  This component will act in a similar way to how the standalone app worked in the previous post.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Create a project reference to <em>PHPBridge.Shared<\/em>.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" src=\"https:\/\/lcigaming.ca\/articles\/wp-content\/uploads\/2025\/09\/Shared-project-reference-client.png\" alt=\"\" class=\"wp-image-319\"\/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This ensures that the server and client components have matching API calls and payload layouts.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Add <em>Services\\ServerRequestService.cs<\/em>:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:clamp(14px, .875rem, 21px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#f2f2f2;color:#2f363c\">C#<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#24292e;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>using PHPBridge.Shared.Model;\nusing System.Net.Http.Json;\n\nnamespace PHPBridge.Client.Services\n{\n    public class ServerRequestService(HttpClient httpClient)\n    {\n        readonly HttpClient client = httpClient;\n\n        public async Task&lt;WeatherForecast[]?> GetWeatherForecasts()\n        {\n            return await client.GetFromJsonAsync&lt;WeatherForecast[]>(\n                $\"{APIConstants.BOUNDARY}\/{APIConstants.WEATHER}\");\n        }\n\n        public async Task&lt;CounterData?> GetCounterData()\n        {\n            return await client.GetFromJsonAsync&lt;CounterData>(\n                $\"{APIConstants.BOUNDARY}\/{APIConstants.COUNTER}\");\n        }\n\n        public async Task&lt;CounterData?> IncrementCounter()\n        {\n            var response = await client.PostAsync(\n                $\"{APIConstants.BOUNDARY}\/{APIConstants.COUNTER}\/{APIConstants.INCREMENT}\", \n                null);\n            return await response.Content.ReadFromJsonAsync&lt;CounterData>();\n        }\n\n        public async Task&lt;CounterData?> DecrementCounter()\n        {\n            var response = await client.PostAsync(\n                $\"{APIConstants.BOUNDARY}\/{APIConstants.COUNTER}\/{APIConstants.DECREMENT}\", \n                null);\n            return await response.Content.ReadFromJsonAsync&lt;CounterData>();\n        }\n    }\n}<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki github-light\" style=\"background-color: #fff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #D73A49\">using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">PHPBridge<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Shared<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Model<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">System<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Net<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Http<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Json<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">namespace<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">PHPBridge<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Client<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Services<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">class<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">ServerRequestService<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #6F42C1\">HttpClient<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">httpClient<\/span><span style=\"color: #24292E\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">readonly<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">HttpClient<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">client<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> httpClient;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">async<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Task<\/span><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #6F42C1\">WeatherForecast<\/span><span style=\"color: #24292E\">[]?&gt; <\/span><span style=\"color: #6F42C1\">GetWeatherForecasts<\/span><span style=\"color: #24292E\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">return<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">await<\/span><span style=\"color: #24292E\"> client.<\/span><span style=\"color: #6F42C1\">GetFromJsonAsync<\/span><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #6F42C1\">WeatherForecast<\/span><span style=\"color: #24292E\">[]&gt;(<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #032F62\">$&quot;{<\/span><span style=\"color: #24292E\">APIConstants<\/span><span style=\"color: #032F62\">.<\/span><span style=\"color: #24292E\">BOUNDARY<\/span><span style=\"color: #032F62\">}\/{<\/span><span style=\"color: #24292E\">APIConstants<\/span><span style=\"color: #032F62\">.<\/span><span style=\"color: #24292E\">WEATHER<\/span><span style=\"color: #032F62\">}&quot;<\/span><span style=\"color: #24292E\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">async<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Task<\/span><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #6F42C1\">CounterData<\/span><span style=\"color: #24292E\">?&gt; <\/span><span style=\"color: #6F42C1\">GetCounterData<\/span><span style=\"color: #24292E\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">return<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">await<\/span><span style=\"color: #24292E\"> client.<\/span><span style=\"color: #6F42C1\">GetFromJsonAsync<\/span><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #6F42C1\">CounterData<\/span><span style=\"color: #24292E\">&gt;(<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #032F62\">$&quot;{<\/span><span style=\"color: #24292E\">APIConstants<\/span><span style=\"color: #032F62\">.<\/span><span style=\"color: #24292E\">BOUNDARY<\/span><span style=\"color: #032F62\">}\/{<\/span><span style=\"color: #24292E\">APIConstants<\/span><span style=\"color: #032F62\">.<\/span><span style=\"color: #24292E\">COUNTER<\/span><span style=\"color: #032F62\">}&quot;<\/span><span style=\"color: #24292E\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">async<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Task<\/span><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #6F42C1\">CounterData<\/span><span style=\"color: #24292E\">?&gt; <\/span><span style=\"color: #6F42C1\">IncrementCounter<\/span><span style=\"color: #24292E\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">var<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">response<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">await<\/span><span style=\"color: #24292E\"> client.<\/span><span style=\"color: #6F42C1\">PostAsync<\/span><span style=\"color: #24292E\">(<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #032F62\">$&quot;{<\/span><span style=\"color: #24292E\">APIConstants<\/span><span style=\"color: #032F62\">.<\/span><span style=\"color: #24292E\">BOUNDARY<\/span><span style=\"color: #032F62\">}\/{<\/span><span style=\"color: #24292E\">APIConstants<\/span><span style=\"color: #032F62\">.<\/span><span style=\"color: #24292E\">COUNTER<\/span><span style=\"color: #032F62\">}\/{<\/span><span style=\"color: #24292E\">APIConstants<\/span><span style=\"color: #032F62\">.<\/span><span style=\"color: #24292E\">INCREMENT<\/span><span style=\"color: #032F62\">}&quot;<\/span><span style=\"color: #24292E\">, <\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #005CC5\">null<\/span><span style=\"color: #24292E\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">return<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">await<\/span><span style=\"color: #24292E\"> response.Content.<\/span><span style=\"color: #6F42C1\">ReadFromJsonAsync<\/span><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #6F42C1\">CounterData<\/span><span style=\"color: #24292E\">&gt;();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">async<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Task<\/span><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #6F42C1\">CounterData<\/span><span style=\"color: #24292E\">?&gt; <\/span><span style=\"color: #6F42C1\">DecrementCounter<\/span><span style=\"color: #24292E\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">var<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">response<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">await<\/span><span style=\"color: #24292E\"> client.<\/span><span style=\"color: #6F42C1\">PostAsync<\/span><span style=\"color: #24292E\">(<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #032F62\">$&quot;{<\/span><span style=\"color: #24292E\">APIConstants<\/span><span style=\"color: #032F62\">.<\/span><span style=\"color: #24292E\">BOUNDARY<\/span><span style=\"color: #032F62\">}\/{<\/span><span style=\"color: #24292E\">APIConstants<\/span><span style=\"color: #032F62\">.<\/span><span style=\"color: #24292E\">COUNTER<\/span><span style=\"color: #032F62\">}\/{<\/span><span style=\"color: #24292E\">APIConstants<\/span><span style=\"color: #032F62\">.<\/span><span style=\"color: #24292E\">DECREMENT<\/span><span style=\"color: #032F62\">}&quot;<\/span><span style=\"color: #24292E\">, <\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #005CC5\">null<\/span><span style=\"color: #24292E\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">return<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">await<\/span><span style=\"color: #24292E\"> response.Content.<\/span><span style=\"color: #6F42C1\">ReadFromJsonAsync<\/span><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #6F42C1\">CounterData<\/span><span style=\"color: #24292E\">&gt;();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Unlike in the previous post, we only need one version of the service for both development and production.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Register the services needed in the client <em>Program.cs<\/em>:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:clamp(14px, .875rem, 21px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-highlight-color:rgba(16, 41, 67, 0.2);line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#f2f2f2;color:#2f363c\">C#<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#24292e;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>using Microsoft.AspNetCore.Components.WebAssembly.Hosting;\nusing PHPBridge.Client.Services;\n\nnamespace PHPBridge.Client\n{\n    internal class Program\n    {\n        static async Task Main(string[] args)\n        {\n            var builder = WebAssemblyHostBuilder.CreateDefault(args);\n\n            builder.Services.AddScoped(\n                sp => new HttpClient { \n                    BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });\n            builder.Services.AddScoped&lt;ServerRequestService>();\n\n            await builder.Build().RunAsync();\n        }\n    }\n}\n<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki github-light\" style=\"background-color: #fff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #D73A49\">using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Microsoft<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">AspNetCore<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Components<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">WebAssembly<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Hosting<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">PHPBridge<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Client<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Services<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">namespace<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">PHPBridge<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Client<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">internal<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">class<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Program<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">static<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">async<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Task<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Main<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\">[] <\/span><span style=\"color: #6F42C1\">args<\/span><span style=\"color: #24292E\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">var<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">builder<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> WebAssemblyHostBuilder.<\/span><span style=\"color: #6F42C1\">CreateDefault<\/span><span style=\"color: #24292E\">(args);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">            builder.Services.<\/span><span style=\"color: #6F42C1\">AddScoped<\/span><span style=\"color: #24292E\">(<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #6F42C1\">sp<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">HttpClient<\/span><span style=\"color: #24292E\"> { <\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">                    BaseAddress <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Uri<\/span><span style=\"color: #24292E\">(builder.HostEnvironment.BaseAddress) });<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">            builder.Services.<\/span><span style=\"color: #6F42C1\">AddScoped<\/span><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #6F42C1\">ServerRequestService<\/span><span style=\"color: #24292E\">&gt;();<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">await<\/span><span style=\"color: #24292E\"> builder.<\/span><span style=\"color: #6F42C1\">Build<\/span><span style=\"color: #24292E\">().<\/span><span style=\"color: #6F42C1\">RunAsync<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">}<\/span><\/span>\n<span class=\"line\"><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">The <em>HttpClient <\/em>used by <em>ServerRequestService <\/em>is set up to use the same URI as used by the browser to fetch the home page.  This URI is also used to fetch support files such as style sheets and javascript code. In this app, this means that everything is routed to the server component built from the <em>PHPBridge <\/em>project, including the GET and POST requests from <em>ServerRequestService<\/em>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">To simplify the changes to the razor pages, modify <em>_Imports.razor<\/em>:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:clamp(14px, .875rem, 21px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-highlight-color:rgba(16, 41, 67, 0.2);line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#f2f2f2;color:#2f363c\">Razor<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#24292e;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>@using System.Net.Http\n@using System.Net.Http.Json\n@using Microsoft.AspNetCore.Components.Forms\n@using Microsoft.AspNetCore.Components.Routing\n@using Microsoft.AspNetCore.Components.Web\n@using static Microsoft.AspNetCore.Components.Web.RenderMode\n@using Microsoft.AspNetCore.Components.Web.Virtualization\n@using Microsoft.JSInterop\n@using PHPBridge.Client\n@using PHPBridge.Client.Services\n@using PHPBridge.Shared.Model\n<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki github-light\" style=\"background-color: #fff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #D73A49\">@using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">System<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Net<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Http<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">@using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">System<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Net<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Http<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Json<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">@using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Microsoft<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">AspNetCore<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Components<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Forms<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">@using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Microsoft<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">AspNetCore<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Components<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Routing<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">@using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Microsoft<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">AspNetCore<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Components<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Web<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">@using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">static<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Microsoft<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">AspNetCore<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Components<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Web<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">RenderMode<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">@using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Microsoft<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">AspNetCore<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Components<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Web<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Virtualization<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">@using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Microsoft<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">JSInterop<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">@using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">PHPBridge<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Client<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D73A49\">@using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">PHPBridge<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Client<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Services<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D73A49\">@using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">PHPBridge<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Shared<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Model<\/span><\/span>\n<span class=\"line\"><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Modify <em>Pages\\Weather.razor<\/em>:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:clamp(14px, .875rem, 21px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#f2f2f2;color:#2f363c\">Razor<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#24292e;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>@page \"\/weather\"\n@inject ServerRequestService ServerRequest\n\n&lt;PageTitle>Weather&lt;\/PageTitle>\n\n&lt;h1>Weather&lt;\/h1>\n\n&lt;p>This component demonstrates showing data.&lt;\/p>\n\n@if (forecasts == null)\n{\n    &lt;p>&lt;em>Loading...&lt;\/em>&lt;\/p>\n}\nelse\n{\n    ...\n}\n\n@code {\n    private WeatherForecast[]? forecasts;\n\n    protected override async Task OnInitializedAsync()\n    {\n        forecasts = await ServerRequest.GetWeatherForecasts();\n    }\n\n}\n<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki github-light\" style=\"background-color: #fff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #D73A49\">@page<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">&quot;\/weather&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">@inject<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">ServerRequestService<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">ServerRequest<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #B31D28; font-style: italic\">PageTitle<\/span><span style=\"color: #24292E\">&gt;Weather&lt;\/<\/span><span style=\"color: #B31D28; font-style: italic\">PageTitle<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #22863A\">h1<\/span><span style=\"color: #24292E\">&gt;Weather&lt;\/<\/span><span style=\"color: #22863A\">h1<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #22863A\">p<\/span><span style=\"color: #24292E\">&gt;This component demonstrates showing data.&lt;\/<\/span><span style=\"color: #22863A\">p<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">@if<\/span><span style=\"color: #24292E\"> (forecasts <\/span><span style=\"color: #D73A49\">==<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">null<\/span><span style=\"color: #24292E\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    &lt;<\/span><span style=\"color: #22863A\">p<\/span><span style=\"color: #24292E\">&gt;&lt;<\/span><span style=\"color: #22863A\">em<\/span><span style=\"color: #24292E\">&gt;Loading...&lt;\/<\/span><span style=\"color: #22863A\">em<\/span><span style=\"color: #24292E\">&gt;&lt;\/<\/span><span style=\"color: #22863A\">p<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">}<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">else<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">..<\/span><span style=\"color: #24292E\">.<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">@code<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">private<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">WeatherForecast<\/span><span style=\"color: #24292E\">[]? <\/span><span style=\"color: #6F42C1\">forecasts<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">protected<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">override<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">async<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Task<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">OnInitializedAsync<\/span><span style=\"color: #24292E\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        forecasts <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">await<\/span><span style=\"color: #24292E\"> ServerRequest.<\/span><span style=\"color: #6F42C1\">GetWeatherForecasts<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">}<\/span><\/span>\n<span class=\"line\"><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Modify Pages\\Counter.razor:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:clamp(14px, .875rem, 21px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#f2f2f2;color:#2f363c\">Razor<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#24292e;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>@page \"\/counter\"\n@inject ServerRequestService ServerRequest\n\n&lt;PageTitle>Counter&lt;\/PageTitle>\n\n&lt;h1>Counter&lt;\/h1>\n\n&lt;p role=\"status\">Current count: @currentCount, last action: @lastAction&lt;\/p>\n\n&lt;button class=\"btn btn-primary\" @onclick=\"IncrementCount\">Click me to increment&lt;\/button>\n&lt;button class=\"btn btn-primary\" @onclick=\"DecrementCount\">Click me to decrement&lt;\/button>\n\n@code {\n    private int currentCount = 0;\n    private CounterData? data;\n    private string lastAction = \"unknown\";\n\n    protected override async Task OnInitializedAsync()\n    {\n        data = await ServerRequest.GetCounterData();\n        currentCount = data?.Count ?? -1;\n        lastAction = data?.Action ?? \"unknown\";\n    }\n\n    private async Task IncrementCount()\n    {\n        data = await ServerRequest.IncrementCounter();\n        currentCount = data?.Count ?? -1;\n        lastAction = data?.Action ?? \"failed to increment\";\n        await InvokeAsync(StateHasChanged);\n    }\n\n    private async Task DecrementCount()\n    {\n        data = await ServerRequest.DecrementCounter();\n        currentCount = data?.Count ?? -1;\n        lastAction = data?.Action ?? \"failed to decrement\";\n        await InvokeAsync(StateHasChanged);\n    }\n}<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki github-light\" style=\"background-color: #fff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #D73A49\">@page<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">&quot;\/counter&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">@inject<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">ServerRequestService<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">ServerRequest<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #B31D28; font-style: italic\">PageTitle<\/span><span style=\"color: #24292E\">&gt;Counter&lt;\/<\/span><span style=\"color: #B31D28; font-style: italic\">PageTitle<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #22863A\">h1<\/span><span style=\"color: #24292E\">&gt;Counter&lt;\/<\/span><span style=\"color: #22863A\">h1<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #22863A\">p<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">role<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;status&quot;<\/span><span style=\"color: #24292E\">&gt;Current count: <\/span><span style=\"color: #D73A49\">@<\/span><span style=\"color: #24292E\">currentCount, last action: <\/span><span style=\"color: #D73A49\">@<\/span><span style=\"color: #24292E\">lastAction&lt;\/<\/span><span style=\"color: #22863A\">p<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #22863A\">button<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">class<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;btn btn-primary&quot;<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">@onclick<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;IncrementCount&quot;<\/span><span style=\"color: #24292E\">&gt;Click me to increment&lt;\/<\/span><span style=\"color: #22863A\">button<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #22863A\">button<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">class<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;btn btn-primary&quot;<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">@onclick<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;DecrementCount&quot;<\/span><span style=\"color: #24292E\">&gt;Click me to decrement&lt;\/<\/span><span style=\"color: #22863A\">button<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">@code<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">private<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">int<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">currentCount<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">0<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">private<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">CounterData<\/span><span style=\"color: #24292E\">? <\/span><span style=\"color: #6F42C1\">data<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">private<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">lastAction<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">&quot;unknown&quot;<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">protected<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">override<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">async<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Task<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">OnInitializedAsync<\/span><span style=\"color: #24292E\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        data <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">await<\/span><span style=\"color: #24292E\"> ServerRequest.<\/span><span style=\"color: #6F42C1\">GetCounterData<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        currentCount <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> data<\/span><span style=\"color: #D73A49\">?<\/span><span style=\"color: #24292E\">.Count <\/span><span style=\"color: #D73A49\">??<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">-<\/span><span style=\"color: #005CC5\">1<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        lastAction <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> data<\/span><span style=\"color: #D73A49\">?<\/span><span style=\"color: #24292E\">.Action <\/span><span style=\"color: #D73A49\">??<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">&quot;unknown&quot;<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">private<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">async<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Task<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">IncrementCount<\/span><span style=\"color: #24292E\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        data <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">await<\/span><span style=\"color: #24292E\"> ServerRequest.<\/span><span style=\"color: #6F42C1\">IncrementCounter<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        currentCount <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> data<\/span><span style=\"color: #D73A49\">?<\/span><span style=\"color: #24292E\">.Count <\/span><span style=\"color: #D73A49\">??<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">-<\/span><span style=\"color: #005CC5\">1<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        lastAction <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> data<\/span><span style=\"color: #D73A49\">?<\/span><span style=\"color: #24292E\">.Action <\/span><span style=\"color: #D73A49\">??<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">&quot;failed to increment&quot;<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">await<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">InvokeAsync<\/span><span style=\"color: #24292E\">(StateHasChanged);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">private<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">async<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Task<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">DecrementCount<\/span><span style=\"color: #24292E\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        data <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">await<\/span><span style=\"color: #24292E\"> ServerRequest.<\/span><span style=\"color: #6F42C1\">DecrementCounter<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        currentCount <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> data<\/span><span style=\"color: #D73A49\">?<\/span><span style=\"color: #24292E\">.Count <\/span><span style=\"color: #D73A49\">??<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">-<\/span><span style=\"color: #005CC5\">1<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        lastAction <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> data<\/span><span style=\"color: #D73A49\">?<\/span><span style=\"color: #24292E\">.Action <\/span><span style=\"color: #D73A49\">??<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">&quot;failed to decrement&quot;<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">await<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">InvokeAsync<\/span><span style=\"color: #24292E\">(StateHasChanged);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">A Dry Run<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">If you debug the app in the development environment you should see it perform much as the app did in the previous post. You can place breakpoints in <em>ServerRequestService <\/em>in the client and <em>API <\/em>in the server to see the requests being created and responded to.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Behind the scenes the development environment includes a web server that handles the transfer of requests and data between the client and server components.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Moving to the Server<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">When we deployed a Blazor Web App to Linux in my first post, we created a Linux service to run the server component, then used Apache proxying to relay requests from the browser or client to this server component.  We will need to accomplish these same tasks in a shared server environment.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Running the Server Component<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">We are assuming that the server being deployed to does not have the dotnet runtime installed. This means that we will need to deploy our app as a self-contained package. This will contain all of the dotnet support files as well as an executable file for the app itself. <\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"709\" height=\"562\" src=\"https:\/\/lcigaming.ca\/articles\/wp-content\/uploads\/2025\/09\/Publish-settings.png\" alt=\"\" class=\"wp-image-250\" srcset=\"https:\/\/lcigaming.ca\/articles\/wp-content\/uploads\/2025\/09\/Publish-settings.png 709w, https:\/\/lcigaming.ca\/articles\/wp-content\/uploads\/2025\/09\/Publish-settings-300x238.png 300w\" sizes=\"auto, (max-width: 709px) 100vw, 709px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The app executable will need to be started in order for it to be able to respond to client requests.  One option for starting the executable is to use the PHP <em>exec <\/em>function, if it is supported on the server.  This would look something like:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:clamp(14px, .875rem, 21px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#f2f2f2;color:#2f363c\">PHP<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#24292e;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>&lt;?php\n\n$address = '127.0.0.1:5000';\n$command = 'nohup .\/PHPBridge --urls http:\/\/$address > \/dev\/null 2>&amp;1 &amp;';\nexec($command);\n\n?><\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki github-light\" style=\"background-color: #fff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #D73A49\">&lt;?<\/span><span style=\"color: #005CC5\">php<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">$address <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">&#39;127.0.0.1:5000&#39;<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">$command <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">&#39;nohup .\/PHPBridge --urls http:\/\/$address &gt; \/dev\/null 2&gt;&amp;1 &amp;&#39;<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #005CC5\">exec<\/span><span style=\"color: #24292E\">($command);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">?&gt;<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">This runs the main executable as a separate process.  The output is suppressed to prevent the <em>exec <\/em>call from hanging.  We could use this snippet as part of <em>index.php<\/em> in the application root, but there are some operational issues to tend with.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If the PHP <em>exec <\/em>function is not supported on the server you wish to deploy to, you will need another mechanism for ensuring that the server component is started. Many shared hosting services allow you to set up CRON jobs for maintenance. This is a possible location for such a mechanism.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The <em>PHPBridge<\/em> process, by default, will run under the same userid that PHP runs under, which on my system is <em>www-root<\/em>.  It is unlikely that the app will run properly under this userid if it runs at all.  As such, you will need <em>setuid <\/em>on the executable so that it runs under the owner id:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:clamp(14px, .875rem, 21px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#f2f2f2;color:#2f363c\">Bash<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#24292e;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>chmod u+s,a+x PHPBridge<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki github-light\" style=\"background-color: #fff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #6F42C1\">chmod<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">u+s,a+x<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">PHPBridge<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">It is also possible that the port selected is already in use, either by a previous invocation of the app or by another process.  We will need a mechanism for selecting a free port.  We will get to that in a moment.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If the app is already running it would be better to simply make use of it rather than launching a new instance.  To do this we can have the server component create a file which we can check for in a PHP script.  Add the following to <em>Program.cs<\/em> in the main <em>PHPBridge<\/em> project:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:clamp(14px, .875rem, 21px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-highlight-color:rgba(16, 41, 67, 0.2);line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#f2f2f2;color:#2f363c\">C#<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#24292e;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>using PHPBridge.Components;\nusing PHPBridge.Engine;\n\nnamespace BlazorSecurityDemo\n{\n    public class Program\n    {\n        public static void Main(string[] args)\n        {\n            var builder = WebApplication.CreateBuilder(args);\n\n            \/\/ Add services to the container.\n            builder.Services.AddRazorComponents()\n                .AddInteractiveServerComponents();\n\n            builder.Services.AddSingleton&lt;ServerState>();\n            \n            var app = builder.Build();\n\n            var addr = new\n            {\n                URLS = app.Urls,\n                Args = args,\n                ConfigURLS = app.Configuration.GetValue&lt;string>(\"URLS\", \"\")\n            };\n\n            string asJSON = JsonSerializer.Serialize(addr);\n            File.WriteAllText(\"addr.json\", asJSON);\n\n            \/\/ Configure the HTTP request pipeline.\n            if (!app.Environment.IsDevelopment())\n            {\n                app.UseExceptionHandler(\"\/Error\");\n                \/\/ The default HSTS value is 30 days...\n                app.UseHsts();\n            }\n\n            app.UseHttpsRedirection();\n\n            app.UseAntiforgery();\n\n            app.MapStaticAssets();\n            app.MapRazorComponents&lt;App>()\n                .AddInteractiveServerRenderMode();\n\n            app.MapApi();\n            \n            app.Run();\n        }\n    }\n}\n<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki github-light\" style=\"background-color: #fff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #D73A49\">using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">PHPBridge<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Components<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">PHPBridge<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Engine<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">namespace<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">BlazorSecurityDemo<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">class<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Program<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">static<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">void<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Main<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\">[] <\/span><span style=\"color: #6F42C1\">args<\/span><span style=\"color: #24292E\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">var<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">builder<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> WebApplication.<\/span><span style=\"color: #6F42C1\">CreateBuilder<\/span><span style=\"color: #24292E\">(args);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #6A737D\">            \/\/ Add services to the container.<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            builder.Services.<\/span><span style=\"color: #6F42C1\">AddRazorComponents<\/span><span style=\"color: #24292E\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                .<\/span><span style=\"color: #6F42C1\">AddInteractiveServerComponents<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            builder.Services.<\/span><span style=\"color: #6F42C1\">AddSingleton<\/span><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #6F42C1\">ServerState<\/span><span style=\"color: #24292E\">&gt;();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">var<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">app<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> builder.<\/span><span style=\"color: #6F42C1\">Build<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">var<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">addr<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">new<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">            {<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">                URLS <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> app.Urls,<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">                Args <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> args,<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">                ConfigURLS <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> app.Configuration.<\/span><span style=\"color: #6F42C1\">GetValue<\/span><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\">&gt;(<\/span><span style=\"color: #032F62\">&quot;URLS&quot;<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #032F62\">&quot;&quot;<\/span><span style=\"color: #24292E\">)<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">            };<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">asJSON<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> JsonSerializer.<\/span><span style=\"color: #6F42C1\">Serialize<\/span><span style=\"color: #24292E\">(addr);<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">            File.<\/span><span style=\"color: #6F42C1\">WriteAllText<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #032F62\">&quot;addr.json&quot;<\/span><span style=\"color: #24292E\">, asJSON);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #6A737D\">            \/\/ Configure the HTTP request pipeline.<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">if<\/span><span style=\"color: #24292E\"> (<\/span><span style=\"color: #D73A49\">!<\/span><span style=\"color: #24292E\">app.Environment.<\/span><span style=\"color: #6F42C1\">IsDevelopment<\/span><span style=\"color: #24292E\">())<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                app.<\/span><span style=\"color: #6F42C1\">UseExceptionHandler<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #032F62\">&quot;\/Error&quot;<\/span><span style=\"color: #24292E\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6A737D\">                \/\/ The default HSTS value is 30 days...<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                app.<\/span><span style=\"color: #6F42C1\">UseHsts<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            app.<\/span><span style=\"color: #6F42C1\">UseHttpsRedirection<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            app.<\/span><span style=\"color: #6F42C1\">UseAntiforgery<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            app.<\/span><span style=\"color: #6F42C1\">MapStaticAssets<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            app.<\/span><span style=\"color: #6F42C1\">MapRazorComponents<\/span><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #6F42C1\">App<\/span><span style=\"color: #24292E\">&gt;()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                .<\/span><span style=\"color: #6F42C1\">AddInteractiveServerRenderMode<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            app.<\/span><span style=\"color: #6F42C1\">MapApi<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            app.<\/span><span style=\"color: #6F42C1\">Run<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">}<\/span><\/span>\n<span class=\"line\"><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Handling the Initial Browser Request<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">For the app from my first post Apache forwarded the initial GET request from the browser to the app server component, which responded with the text of the home page. We can replicate this in PHP using cURL.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Create <em>index.php<\/em> at the root of the <em>PHPBridge <\/em>project:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:clamp(14px, .875rem, 21px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#24292e;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#f2f2f2;color:#2f363c\">PHP<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#24292e;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>&lt;?php\n\n\/\/ see if server is already running\n$addr = file_get_contents('addr.json');\n\nif ($addr) {\n    $urls = json_decode($addr, true);\n    if (isset($urls&#91;'ConfigURLS'&#93;)) {\n        $url = $urls&#91;'ConfigURLS'&#93;;\n        if (str_contains($url, ';')) {\n            $url = substr($url, 0, strpos($url,';') - 1);\n        }\n\n        $urlParts = explode(\":\", $url);\n        $url = substr($urlParts&#91;1&#93;, 2);\n        $port = $urlParts&#91;2&#93;;\n\n        \/\/ check if port is open\n        $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);\n        $result = socket_connect($socket, $url, $port);\n        if (!$result) {\n            unset($url);\n            unset($port);\n        }\n\n        socket_close($socket);\n    }\n}\n\n\/\/ start the server component if necessary\nif (!isset($url)) {\n\n    $host = '127.0.0.1';\n    $startPort = 0;\n\n    $server = stream_socket_server(\"tcp:\/\/$host:$startPort\", $errno, $errstr);\n    if ($server) {\n        $address = stream_socket_get_name($server, false);\n        fclose($server);\n\n        $addrParts = explode(\":\", $address);\n        $url = $addrParts&#91;0&#93;;\n        $port = $addrParts&#91;1&#93;;\n\n        $command = \"nohup .\/PHPBridge --urls http:\/\/$address > \/dev\/null 2>&amp;1 &amp;\";\n        exec($command);\n\n        \/\/ allow server to start\n        sleep(1);\n    } else {\n        die($errno);\n    }\n}\n\n\/\/ forward headers from client\nforeach (getallheaders() as $key => $value) {\n    $headers&#91;$key&#93; = $value;\n}\n\n$ch = curl_init();\ncurl_setopt($ch, CURLOPT_URL, $url);\ncurl_setopt($ch, CURLOPT_PORT, $port);\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n\ncurl_setopt($ch, CURLOPT_HTTPHEADER, $headers);\n\n$response = curl_exec($ch);\n\nif (curl_errno($ch)) {\n    die(curl_error($ch));\n}\n\n$httpStatus = curl_getinfo($ch, CURLINFO_HTTP_CODE);\n$httpType = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);\n\ncurl_close($ch);\n\nheader(\"Content-Type: $httpType\");\nhttp_response_code($httpStatus);\n\necho $response;\n\n?><\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki github-light\" style=\"background-color: #fff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #D73A49\">&lt;?<\/span><span style=\"color: #005CC5\">php<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #6A737D\">\/\/ see if server is already running<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">$addr <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">file_get_contents<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #032F62\">&#39;addr.json&#39;<\/span><span style=\"color: #24292E\">);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">if<\/span><span style=\"color: #24292E\"> ($addr) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    $urls <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">json_decode<\/span><span style=\"color: #24292E\">($addr, <\/span><span style=\"color: #005CC5\">true<\/span><span style=\"color: #24292E\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">if<\/span><span style=\"color: #24292E\"> (<\/span><span style=\"color: #005CC5\">isset<\/span><span style=\"color: #24292E\">($urls&#91;<\/span><span style=\"color: #032F62\">&#39;ConfigURLS&#39;<\/span><span style=\"color: #24292E\">&#93;)) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        $url <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> $urls&#91;<\/span><span style=\"color: #032F62\">&#39;ConfigURLS&#39;<\/span><span style=\"color: #24292E\">&#93;;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">if<\/span><span style=\"color: #24292E\"> (<\/span><span style=\"color: #6F42C1\">str_contains<\/span><span style=\"color: #24292E\">($url, <\/span><span style=\"color: #032F62\">&#39;;&#39;<\/span><span style=\"color: #24292E\">)) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            $url <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">substr<\/span><span style=\"color: #24292E\">($url, <\/span><span style=\"color: #005CC5\">0<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #005CC5\">strpos<\/span><span style=\"color: #24292E\">($url,<\/span><span style=\"color: #032F62\">&#39;;&#39;<\/span><span style=\"color: #24292E\">) <\/span><span style=\"color: #D73A49\">-<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">1<\/span><span style=\"color: #24292E\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        $urlParts <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">explode<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #032F62\">&quot;:&quot;<\/span><span style=\"color: #24292E\">, $url);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        $url <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">substr<\/span><span style=\"color: #24292E\">($urlParts&#91;<\/span><span style=\"color: #005CC5\">1<\/span><span style=\"color: #24292E\">&#93;, <\/span><span style=\"color: #005CC5\">2<\/span><span style=\"color: #24292E\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        $port <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> $urlParts&#91;<\/span><span style=\"color: #005CC5\">2<\/span><span style=\"color: #24292E\">&#93;;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #6A737D\">\/\/ check if port is open<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        $socket <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">socket_create<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #005CC5\">AF_INET<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #005CC5\">SOCK_STREAM<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #005CC5\">SOL_TCP<\/span><span style=\"color: #24292E\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        $result <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">socket_connect<\/span><span style=\"color: #24292E\">($socket, $url, $port);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">if<\/span><span style=\"color: #24292E\"> (<\/span><span style=\"color: #D73A49\">!<\/span><span style=\"color: #24292E\">$result) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #005CC5\">unset<\/span><span style=\"color: #24292E\">($url);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #005CC5\">unset<\/span><span style=\"color: #24292E\">($port);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #005CC5\">socket_close<\/span><span style=\"color: #24292E\">($socket);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #6A737D\">\/\/ start the server component if necessary<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">if<\/span><span style=\"color: #24292E\"> (<\/span><span style=\"color: #D73A49\">!<\/span><span style=\"color: #005CC5\">isset<\/span><span style=\"color: #24292E\">($url)) {<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    $host <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">&#39;127.0.0.1&#39;<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    $startPort <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">0<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    $server <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">stream_socket_server<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #032F62\">&quot;tcp:\/\/<\/span><span style=\"color: #24292E\">$host<\/span><span style=\"color: #032F62\">:<\/span><span style=\"color: #24292E\">$startPort<\/span><span style=\"color: #032F62\">&quot;<\/span><span style=\"color: #24292E\">, $errno, $errstr);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">if<\/span><span style=\"color: #24292E\"> ($server) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        $address <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">stream_socket_get_name<\/span><span style=\"color: #24292E\">($server, <\/span><span style=\"color: #005CC5\">false<\/span><span style=\"color: #24292E\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #005CC5\">fclose<\/span><span style=\"color: #24292E\">($server);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        $addrParts <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">explode<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #032F62\">&quot;:&quot;<\/span><span style=\"color: #24292E\">, $address);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        $url <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> $addrParts&#91;<\/span><span style=\"color: #005CC5\">0<\/span><span style=\"color: #24292E\">&#93;;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        $port <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> $addrParts&#91;<\/span><span style=\"color: #005CC5\">1<\/span><span style=\"color: #24292E\">&#93;;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        $command <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">&quot;nohup .\/PHPBridge --urls http:\/\/<\/span><span style=\"color: #24292E\">$address<\/span><span style=\"color: #032F62\"> &gt; \/dev\/null 2&gt;&amp;1 &amp;&quot;<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #005CC5\">exec<\/span><span style=\"color: #24292E\">($command);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #6A737D\">\/\/ allow server to start<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #005CC5\">sleep<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #005CC5\">1<\/span><span style=\"color: #24292E\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    } <\/span><span style=\"color: #D73A49\">else<\/span><span style=\"color: #24292E\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">die<\/span><span style=\"color: #24292E\">($errno);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #6A737D\">\/\/ forward headers from client<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">foreach<\/span><span style=\"color: #24292E\"> (<\/span><span style=\"color: #005CC5\">getallheaders<\/span><span style=\"color: #24292E\">() <\/span><span style=\"color: #D73A49\">as<\/span><span style=\"color: #24292E\"> $key <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> $value) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    $headers&#91;$key&#93; <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> $value;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">$ch <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">curl_init<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #005CC5\">curl_setopt<\/span><span style=\"color: #24292E\">($ch, <\/span><span style=\"color: #005CC5\">CURLOPT_URL<\/span><span style=\"color: #24292E\">, $url);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #005CC5\">curl_setopt<\/span><span style=\"color: #24292E\">($ch, <\/span><span style=\"color: #005CC5\">CURLOPT_PORT<\/span><span style=\"color: #24292E\">, $port);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #005CC5\">curl_setopt<\/span><span style=\"color: #24292E\">($ch, <\/span><span style=\"color: #005CC5\">CURLOPT_RETURNTRANSFER<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #005CC5\">true<\/span><span style=\"color: #24292E\">);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #005CC5\">curl_setopt<\/span><span style=\"color: #24292E\">($ch, <\/span><span style=\"color: #005CC5\">CURLOPT_HTTPHEADER<\/span><span style=\"color: #24292E\">, $headers);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">$response <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">curl_exec<\/span><span style=\"color: #24292E\">($ch);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">if<\/span><span style=\"color: #24292E\"> (<\/span><span style=\"color: #005CC5\">curl_errno<\/span><span style=\"color: #24292E\">($ch)) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">die<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #005CC5\">curl_error<\/span><span style=\"color: #24292E\">($ch));<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">$httpStatus <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">curl_getinfo<\/span><span style=\"color: #24292E\">($ch, <\/span><span style=\"color: #005CC5\">CURLINFO_HTTP_CODE<\/span><span style=\"color: #24292E\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">$httpType <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">curl_getinfo<\/span><span style=\"color: #24292E\">($ch, <\/span><span style=\"color: #005CC5\">CURLINFO_CONTENT_TYPE<\/span><span style=\"color: #24292E\">);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #005CC5\">curl_close<\/span><span style=\"color: #24292E\">($ch);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #005CC5\">header<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #032F62\">&quot;Content-Type: <\/span><span style=\"color: #24292E\">$httpType<\/span><span style=\"color: #032F62\">&quot;<\/span><span style=\"color: #24292E\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #005CC5\">http_response_code<\/span><span style=\"color: #24292E\">($httpStatus);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #005CC5\">echo<\/span><span style=\"color: #24292E\"> $response;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">?&gt;<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">This file has three main parts.<\/p>\n\n\n\n<dl class=\"wp-block-description-list-block-description-list\"><dt style=\"--termsMarginTop:0px;--termsMarginBottom:0px;--termsMarginLeft:0px;--termsMarginRight:0px;--termsPaddingTop:0px;--termsPaddingBottom:false;--termsPaddingLeft:0px;--termsPaddingRight:0px\"><strong>Lines 3-28<\/strong><\/dt><dd style=\"--descriptionsMarginTop:0px;--descriptionsMarginBottom:0px;--descriptionsMarginLeft:0px;--descriptionsMarginRight:0px;--descriptionsMarginInlineStart:10%;--descriptionsPaddingTop:0px;--descriptionsPaddingBottom:0px;--descriptionsPaddingLeft:0px;--descriptionsPaddingRight:0px\">Check to see if the Blazor server component is already running.  If it is, get its URL.<\/dd><dt style=\"--termsMarginTop:0px;--termsMarginBottom:0px;--termsMarginLeft:0px;--termsMarginRight:0px;--termsPaddingTop:0px;--termsPaddingBottom:false;--termsPaddingLeft:0px;--termsPaddingRight:0px\"><strong>Lines 30-53<\/strong><\/dt><dd style=\"--descriptionsMarginTop:0px;--descriptionsMarginBottom:0px;--descriptionsMarginLeft:0px;--descriptionsMarginRight:0px;--descriptionsMarginInlineStart:10%;--descriptionsPaddingTop:0px;--descriptionsPaddingBottom:0px;--descriptionsPaddingLeft:0px;--descriptionsPaddingRight:0px\">If the Blazor server component is not running, find a free port and start the server component using that port.<\/dd><dt style=\"--termsMarginTop:0px;--termsMarginBottom:0px;--termsMarginLeft:0px;--termsMarginRight:0px;--termsPaddingTop:0px;--termsPaddingBottom:false;--termsPaddingLeft:0px;--termsPaddingRight:0px\"><strong>Lines 55-81<\/strong><\/dt><dd style=\"--descriptionsMarginTop:0px;--descriptionsMarginBottom:0px;--descriptionsMarginLeft:0px;--descriptionsMarginRight:0px;--descriptionsMarginInlineStart:10%;--descriptionsPaddingTop:0px;--descriptionsPaddingBottom:0px;--descriptionsPaddingLeft:0px;--descriptionsPaddingRight:0px\">Forward the current request to the server component, and return its response to the browser.<\/dd><\/dl>\n\n\n\n<p class=\"wp-block-paragraph\">The check for a running server component depends on the existence file <em>addr.json<\/em> that is created by the component.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The second section executes if there is no server URL available, either because <em>addr.json<\/em> does not exist or it references a server that is not responding.  This section makes use of the fact that most modern Linux distributions allow using port zero (&#8216;0&#8217;) for a socket open call to indicate that the system can use any available non-system port to satisfy it.  Once the new server URL is established the app is started.  We introduce a slight delay to allow the app to start before sending any requests.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">With a running app we can forward the original request and echo the response.  The browser should receive the home page HTML in response to its GET request.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In order for this page to be usable it needs to be published to the server in a suitable format. Since the file is not contained in the <em>wwwroot <\/em>folder of the project it will not automatically be included as part of the published package. To make sure this happens set the <em>Copy to Output Directory<\/em> setting to <em>Copy always<\/em> or <em>Copy if newer<\/em>.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" src=\"https:\/\/lcigaming.ca\/articles\/wp-content\/uploads\/2025\/09\/Index-php-settings.png\" alt=\"\" class=\"wp-image-333\"\/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Furthermore, the file will need to need to be saved as a Linux text file.  If you are using Windows for development, this is not the default.  In Visual Studio 2026, which is still in early release, this can be done on a per-file basis.  In Visual Studio 2022 you will need to fix this in two places.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In <em>Tools-&gt;Options-&gt;Environment-&gt;Documents<\/em>, check <em>Save files with a specific encoding<\/em> and select <em>Unicode (UTF-8 without signature) &#8211; Code page 65001<\/em>.  This removes the BOM (Byte Order Mark) from the beginning of the file.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" src=\"https:\/\/lcigaming.ca\/articles\/wp-content\/uploads\/2025\/09\/UTF-without-signature.png\" alt=\"\" class=\"wp-image-334\"\/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">You will also need to change the line endings from the default CRLF that Windows uses to the LF that Linux uses.  This can be changed at the bottom right of the editor window.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" src=\"https:\/\/lcigaming.ca\/articles\/wp-content\/uploads\/2025\/09\/LF-line-end.png\" alt=\"\" class=\"wp-image-335\"\/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Click on this setting to display a pop-up menu.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Handling Subsequent Requests<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">After the home page is loaded the browser issues GET requests for the resources it needs, including CSS, Javascript, and Wasm files.  The requests need to be forwarded to the server component.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In my first post we used <em>ProxyPass <\/em>statements in the Apache configuration to achieve this. We don&#8217;t have this option in a shared server environment, but we can get close through the use of PHP and <em>.htaccess<\/em> files.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Create <em>.htaccess<\/em> at the root of the <em>PHPBridge<\/em> project.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:clamp(14px, .875rem, 21px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#f2f2f2;color:#2f363c\">Apache<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#24292e;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>RewriteEngine on\nRewriteRule ^(&#91;^\/&#93;+)\/(&#91;^\/&#93;+)\/(&#91;^\/&#93;+)\/(&#91;^\/&#93;+)\/(&#91;^\/&#93;+)\/?$ proxy.php?level1=$1&amp;level2=$2&amp;level3=$3&amp;level4=$4&amp;level5=$5 &#91;L,QSA&#93;\nRewriteRule ^(&#91;^\/&#93;+)\/(&#91;^\/&#93;+)\/(&#91;^\/&#93;+)\/(&#91;^\/&#93;+)\/?$ proxy.php?level1=$1&amp;level2=$2&amp;level3=$3&amp;level4=$4 &#91;L,QSA&#93;\nRewriteRule ^(&#91;^\/&#93;+)\/(&#91;^\/&#93;+)\/(&#91;^\/&#93;+)\/?$ proxy.php?level1=$1&amp;level2=$2&amp;level3=$3 &#91;L,QSA&#93;\nRewriteRule ^(&#91;^\/&#93;+)\/(&#91;^\/&#93;+)\/?$ proxy.php?level1=$1&amp;level2=$2 &#91;L,QSA&#93;\nRewriteRule ^(&#91;^\/&#93;+.css)$ proxy.php?level1=$1 &#91;L,QSA&#93;<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki github-light\" style=\"background-color: #fff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #D73A49\">RewriteEngine<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">on<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">RewriteRule<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">^(&#91;^\/&#93;+)\/(&#91;^\/&#93;+)\/(&#91;^\/&#93;+)\/(&#91;^\/&#93;+)\/(&#91;^\/&#93;+)\/?$<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">proxy.php?level1=$1&amp;level2=$2&amp;level3=$3&amp;level4=$4&amp;level5=$5<\/span><span style=\"color: #24292E\"> &#91;L,QSA&#93;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">RewriteRule<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">^(&#91;^\/&#93;+)\/(&#91;^\/&#93;+)\/(&#91;^\/&#93;+)\/(&#91;^\/&#93;+)\/?$<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">proxy.php?level1=$1&amp;level2=$2&amp;level3=$3&amp;level4=$4<\/span><span style=\"color: #24292E\"> &#91;L,QSA&#93;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">RewriteRule<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">^(&#91;^\/&#93;+)\/(&#91;^\/&#93;+)\/(&#91;^\/&#93;+)\/?$<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">proxy.php?level1=$1&amp;level2=$2&amp;level3=$3<\/span><span style=\"color: #24292E\"> &#91;L,QSA&#93;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">RewriteRule<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">^(&#91;^\/&#93;+)\/(&#91;^\/&#93;+)\/?$<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">proxy.php?level1=$1&amp;level2=$2<\/span><span style=\"color: #24292E\"> &#91;L,QSA&#93;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">RewriteRule<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">^(&#91;^\/&#93;+.css)$<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">proxy.php?level1=$1<\/span><span style=\"color: #24292E\"> &#91;L,QSA&#93;<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This forwards most requests to <em>proxy.php<\/em> with multiple levels in the path being converted to multiple parameters in the request. This means that, for example,<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:clamp(14px, .875rem, 21px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#f2f2f2;color:#2f363c\">HTTP<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#24292e;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>GET \/PHPBridge\/lib\/bootstrap\/dist\/css\/bootstrap.min.46ein0sx1k.css<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki github-light\" style=\"background-color: #fff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #D73A49\">GET<\/span><span style=\"color: #24292E\"> \/PHPBridge\/lib\/bootstrap\/dist\/css\/bootstrap.min.46ein0sx1k.css<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">gets converted to<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:clamp(14px, .875rem, 21px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#f2f2f2;color:#2f363c\">HTTP<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#24292e;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>GET proxy.php?level1=lib,level2=bootstrap,level3=dist,level4=css,level5=bootstrap.min.46ein0sx1k.css<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki github-light\" style=\"background-color: #fff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #D73A49\">GET<\/span><span style=\"color: #24292E\"> proxy.php?level1=lib,level2=bootstrap,level3=dist,level4=css,level5=bootstrap.min.46ein0sx1k.css<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Create <em>proxy.php<\/em> at the root of the <em>PHPBridge<\/em> project.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:clamp(14px, .875rem, 21px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#f2f2f2;color:#2f363c\">PHP<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#24292e;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>&lt;?php\n\n\/\/\n\/\/ takes query parameters level1-5\n\/\/\n\n\/\/ get url from running server\n$addr = file_get_contents('addr.json');\n\nif ($addr) {\n    $urls = json_decode($addr, true);\n    if (isset($urls&#91;'ConfigURLS'&#93;)) {\n        $url = $urls&#91;'ConfigURLS'&#93;;\n        if (str_contains($url, ';')) {\n            $url = substr($url, 0, strpos($url, ';') - 1);\n        }\n\n        $urlParts = explode(\":\", $url);\n        $url = substr($urlParts&#91;1&#93;, 2);\n        $port = $urlParts&#91;2&#93;;\n    }\n} else {\n    die(500);\n}\n\n$path = $url;\nif (isset($_GET&#91;\"level1\"&#93;)) {\n    $path = $path . \"\/\" . $_GET&#91;\"level1\"&#93;;\n}\nif (isset($_GET&#91;\"level2\"&#93;)) {\n    $path = $path . \"\/\" . $_GET&#91;\"level2\"&#93;;\n}\nif (isset($_GET&#91;\"level3\"&#93;)) {\n    $path = $path . \"\/\" . $_GET&#91;\"level3\"&#93;;\n}\nif (isset($_GET&#91;\"level4\"&#93;)) {\n    $path = $path . \"\/\" . $_GET&#91;\"level4\"&#93;;\n}\nif (isset($_GET&#91;\"level5\"&#93;)) {\n    $path = $path . \"\/\" . $_GET&#91;\"level5\"&#93;;\n}\n\n$ch = curl_init();\ncurl_setopt($ch, CURLOPT_URL, $path);\ncurl_setopt($ch, CURLOPT_PORT, $port);\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n\n\/\/ forward headers from client\nforeach (getallheaders() as $key => $value) {\n    $headers&#91;$key&#93; = $value;\n}\n\ncurl_setopt($ch, CURLOPT_HTTPHEADER, $headers);\n\n\/\/ forward appropriate verb\nswitch ($_SERVER&#91;'REQUEST_METHOD'&#93;) {\n    case 'POST':\n        curl_setopt($ch, CURLOPT_POST, true);\n        curl_setopt($ch, CURLOPT_POSTFIELDS, file_get_contents('php:\/\/input'));\n        break;\n    case 'PUT':\n        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');\n        curl_setopt($ch, CURLOPT_POSTFIELDS, file_get_contents('php:\/\/input'));\n        break;\n    case 'DELETE':\n        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');\n        break;\n    case 'PATCH':\n        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PATCH');\n        curl_setopt($ch, CURLOPT_POSTFIELDS, file_get_contents('php:\/\/input'));\n        break;\n}\n\n$response = curl_exec($ch);\n\nif (curl_errno($ch)) {\n    $errno = curl_errno($ch);\n    $errmsg = curl_error($ch);\n    die(curl_error($ch));\n}\n\n$httpStatus = curl_getinfo($ch, CURLINFO_HTTP_CODE);\n$httpType = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);\n\ncurl_close($ch);\n\nheader(\"Content-Type: $httpType\");\nhttp_response_code($httpStatus);\n\necho $response;\n\n?><\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki github-light\" style=\"background-color: #fff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #D73A49\">&lt;?<\/span><span style=\"color: #005CC5\">php<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #6A737D\">\/\/<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6A737D\">\/\/ takes query parameters level1-5<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6A737D\">\/\/<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #6A737D\">\/\/ get url from running server<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">$addr <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">file_get_contents<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #032F62\">&#39;addr.json&#39;<\/span><span style=\"color: #24292E\">);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">if<\/span><span style=\"color: #24292E\"> ($addr) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    $urls <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">json_decode<\/span><span style=\"color: #24292E\">($addr, <\/span><span style=\"color: #005CC5\">true<\/span><span style=\"color: #24292E\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">if<\/span><span style=\"color: #24292E\"> (<\/span><span style=\"color: #005CC5\">isset<\/span><span style=\"color: #24292E\">($urls&#91;<\/span><span style=\"color: #032F62\">&#39;ConfigURLS&#39;<\/span><span style=\"color: #24292E\">&#93;)) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        $url <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> $urls&#91;<\/span><span style=\"color: #032F62\">&#39;ConfigURLS&#39;<\/span><span style=\"color: #24292E\">&#93;;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">if<\/span><span style=\"color: #24292E\"> (<\/span><span style=\"color: #6F42C1\">str_contains<\/span><span style=\"color: #24292E\">($url, <\/span><span style=\"color: #032F62\">&#39;;&#39;<\/span><span style=\"color: #24292E\">)) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            $url <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">substr<\/span><span style=\"color: #24292E\">($url, <\/span><span style=\"color: #005CC5\">0<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #005CC5\">strpos<\/span><span style=\"color: #24292E\">($url, <\/span><span style=\"color: #032F62\">&#39;;&#39;<\/span><span style=\"color: #24292E\">) <\/span><span style=\"color: #D73A49\">-<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">1<\/span><span style=\"color: #24292E\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        $urlParts <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">explode<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #032F62\">&quot;:&quot;<\/span><span style=\"color: #24292E\">, $url);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        $url <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">substr<\/span><span style=\"color: #24292E\">($urlParts&#91;<\/span><span style=\"color: #005CC5\">1<\/span><span style=\"color: #24292E\">&#93;, <\/span><span style=\"color: #005CC5\">2<\/span><span style=\"color: #24292E\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        $port <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> $urlParts&#91;<\/span><span style=\"color: #005CC5\">2<\/span><span style=\"color: #24292E\">&#93;;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">} <\/span><span style=\"color: #D73A49\">else<\/span><span style=\"color: #24292E\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">die<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #005CC5\">500<\/span><span style=\"color: #24292E\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">$path <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> $url;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">if<\/span><span style=\"color: #24292E\"> (<\/span><span style=\"color: #005CC5\">isset<\/span><span style=\"color: #24292E\">($_GET&#91;<\/span><span style=\"color: #032F62\">&quot;level1&quot;<\/span><span style=\"color: #24292E\">&#93;)) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    $path <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> $path <\/span><span style=\"color: #D73A49\">.<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">&quot;\/&quot;<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">.<\/span><span style=\"color: #24292E\"> $_GET&#91;<\/span><span style=\"color: #032F62\">&quot;level1&quot;<\/span><span style=\"color: #24292E\">&#93;;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">}<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">if<\/span><span style=\"color: #24292E\"> (<\/span><span style=\"color: #005CC5\">isset<\/span><span style=\"color: #24292E\">($_GET&#91;<\/span><span style=\"color: #032F62\">&quot;level2&quot;<\/span><span style=\"color: #24292E\">&#93;)) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    $path <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> $path <\/span><span style=\"color: #D73A49\">.<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">&quot;\/&quot;<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">.<\/span><span style=\"color: #24292E\"> $_GET&#91;<\/span><span style=\"color: #032F62\">&quot;level2&quot;<\/span><span style=\"color: #24292E\">&#93;;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">}<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">if<\/span><span style=\"color: #24292E\"> (<\/span><span style=\"color: #005CC5\">isset<\/span><span style=\"color: #24292E\">($_GET&#91;<\/span><span style=\"color: #032F62\">&quot;level3&quot;<\/span><span style=\"color: #24292E\">&#93;)) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    $path <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> $path <\/span><span style=\"color: #D73A49\">.<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">&quot;\/&quot;<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">.<\/span><span style=\"color: #24292E\"> $_GET&#91;<\/span><span style=\"color: #032F62\">&quot;level3&quot;<\/span><span style=\"color: #24292E\">&#93;;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">}<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">if<\/span><span style=\"color: #24292E\"> (<\/span><span style=\"color: #005CC5\">isset<\/span><span style=\"color: #24292E\">($_GET&#91;<\/span><span style=\"color: #032F62\">&quot;level4&quot;<\/span><span style=\"color: #24292E\">&#93;)) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    $path <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> $path <\/span><span style=\"color: #D73A49\">.<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">&quot;\/&quot;<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">.<\/span><span style=\"color: #24292E\"> $_GET&#91;<\/span><span style=\"color: #032F62\">&quot;level4&quot;<\/span><span style=\"color: #24292E\">&#93;;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">}<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">if<\/span><span style=\"color: #24292E\"> (<\/span><span style=\"color: #005CC5\">isset<\/span><span style=\"color: #24292E\">($_GET&#91;<\/span><span style=\"color: #032F62\">&quot;level5&quot;<\/span><span style=\"color: #24292E\">&#93;)) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    $path <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> $path <\/span><span style=\"color: #D73A49\">.<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">&quot;\/&quot;<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">.<\/span><span style=\"color: #24292E\"> $_GET&#91;<\/span><span style=\"color: #032F62\">&quot;level5&quot;<\/span><span style=\"color: #24292E\">&#93;;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">$ch <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">curl_init<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #005CC5\">curl_setopt<\/span><span style=\"color: #24292E\">($ch, <\/span><span style=\"color: #005CC5\">CURLOPT_URL<\/span><span style=\"color: #24292E\">, $path);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #005CC5\">curl_setopt<\/span><span style=\"color: #24292E\">($ch, <\/span><span style=\"color: #005CC5\">CURLOPT_PORT<\/span><span style=\"color: #24292E\">, $port);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #005CC5\">curl_setopt<\/span><span style=\"color: #24292E\">($ch, <\/span><span style=\"color: #005CC5\">CURLOPT_RETURNTRANSFER<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #005CC5\">true<\/span><span style=\"color: #24292E\">);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #6A737D\">\/\/ forward headers from client<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">foreach<\/span><span style=\"color: #24292E\"> (<\/span><span style=\"color: #005CC5\">getallheaders<\/span><span style=\"color: #24292E\">() <\/span><span style=\"color: #D73A49\">as<\/span><span style=\"color: #24292E\"> $key <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> $value) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    $headers&#91;$key&#93; <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> $value;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #005CC5\">curl_setopt<\/span><span style=\"color: #24292E\">($ch, <\/span><span style=\"color: #005CC5\">CURLOPT_HTTPHEADER<\/span><span style=\"color: #24292E\">, $headers);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #6A737D\">\/\/ forward appropriate verb<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">switch<\/span><span style=\"color: #24292E\"> ($_SERVER&#91;<\/span><span style=\"color: #032F62\">&#39;REQUEST_METHOD&#39;<\/span><span style=\"color: #24292E\">&#93;) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">case<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">&#39;POST&#39;<\/span><span style=\"color: #24292E\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #005CC5\">curl_setopt<\/span><span style=\"color: #24292E\">($ch, <\/span><span style=\"color: #005CC5\">CURLOPT_POST<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #005CC5\">true<\/span><span style=\"color: #24292E\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #005CC5\">curl_setopt<\/span><span style=\"color: #24292E\">($ch, <\/span><span style=\"color: #005CC5\">CURLOPT_POSTFIELDS<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #005CC5\">file_get_contents<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #032F62\">&#39;php:\/\/input&#39;<\/span><span style=\"color: #24292E\">));<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">break<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">case<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">&#39;PUT&#39;<\/span><span style=\"color: #24292E\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #005CC5\">curl_setopt<\/span><span style=\"color: #24292E\">($ch, <\/span><span style=\"color: #005CC5\">CURLOPT_CUSTOMREQUEST<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #032F62\">&#39;PUT&#39;<\/span><span style=\"color: #24292E\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #005CC5\">curl_setopt<\/span><span style=\"color: #24292E\">($ch, <\/span><span style=\"color: #005CC5\">CURLOPT_POSTFIELDS<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #005CC5\">file_get_contents<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #032F62\">&#39;php:\/\/input&#39;<\/span><span style=\"color: #24292E\">));<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">break<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">case<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">&#39;<\/span><span style=\"color: #D73A49\">DELETE<\/span><span style=\"color: #032F62\">&#39;<\/span><span style=\"color: #24292E\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #005CC5\">curl_setopt<\/span><span style=\"color: #24292E\">($ch, <\/span><span style=\"color: #005CC5\">CURLOPT_CUSTOMREQUEST<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #032F62\">&#39;<\/span><span style=\"color: #D73A49\">DELETE<\/span><span style=\"color: #032F62\">&#39;<\/span><span style=\"color: #24292E\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">break<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">case<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">&#39;PATCH&#39;<\/span><span style=\"color: #24292E\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #005CC5\">curl_setopt<\/span><span style=\"color: #24292E\">($ch, <\/span><span style=\"color: #005CC5\">CURLOPT_CUSTOMREQUEST<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #032F62\">&#39;PATCH&#39;<\/span><span style=\"color: #24292E\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #005CC5\">curl_setopt<\/span><span style=\"color: #24292E\">($ch, <\/span><span style=\"color: #005CC5\">CURLOPT_POSTFIELDS<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #005CC5\">file_get_contents<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #032F62\">&#39;php:\/\/input&#39;<\/span><span style=\"color: #24292E\">));<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">break<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">$response <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">curl_exec<\/span><span style=\"color: #24292E\">($ch);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">if<\/span><span style=\"color: #24292E\"> (<\/span><span style=\"color: #005CC5\">curl_errno<\/span><span style=\"color: #24292E\">($ch)) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    $errno <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">curl_errno<\/span><span style=\"color: #24292E\">($ch);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    $errmsg <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">curl_error<\/span><span style=\"color: #24292E\">($ch);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">die<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #005CC5\">curl_error<\/span><span style=\"color: #24292E\">($ch));<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">$httpStatus <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">curl_getinfo<\/span><span style=\"color: #24292E\">($ch, <\/span><span style=\"color: #005CC5\">CURLINFO_HTTP_CODE<\/span><span style=\"color: #24292E\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">$httpType <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">curl_getinfo<\/span><span style=\"color: #24292E\">($ch, <\/span><span style=\"color: #005CC5\">CURLINFO_CONTENT_TYPE<\/span><span style=\"color: #24292E\">);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #005CC5\">curl_close<\/span><span style=\"color: #24292E\">($ch);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #005CC5\">header<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #032F62\">&quot;Content-Type: <\/span><span style=\"color: #24292E\">$httpType<\/span><span style=\"color: #032F62\">&quot;<\/span><span style=\"color: #24292E\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #005CC5\">http_response_code<\/span><span style=\"color: #24292E\">($httpStatus);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #005CC5\">echo<\/span><span style=\"color: #24292E\"> $response;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">?&gt;<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This script converts the parameters back into path segments and forwards this to the server component.  The response is echoed back to the requestor.  We need to ensure that the content type is correct so that the browser will correctly interpret CSS, Javascript, etc.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">As with <em>index.php<\/em>, both <em>.htaccess<\/em> and <em>proxy.php<\/em> need to be published to the server, so also need the <em>Copy to Output Directory<\/em> and line ending <em>LF <\/em>set.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The resource requests from the browser for the home page all use the GET HTTP verb, but our API requests also use POST for some operations.  The <em>proxy.php<\/em> script will pass on the correct verb to the server component so that the appropriate logic is invoked.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">I have demonstrated that a client-server Blazor web app can be supported through PHP and .htaccess.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">I have not addressed application security, but I have provided a way to create a client-server app entirely in C#, debug it in the development environment, and deploy it with some support files to a shared server.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n","protected":false},"excerpt":{"rendered":"<p>This post will show how to run a client-server Blazor app on a shared Linux server using PHP as an intermediary.<\/p>\n","protected":false},"author":1,"featured_media":305,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"om_disable_all_campaigns":false,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"_themeisle_gutenberg_block_has_review":false,"footnotes":""},"categories":[10],"tags":[],"class_list":["post-299","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-development"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/lcigaming.ca\/articles\/wp-json\/wp\/v2\/posts\/299","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/lcigaming.ca\/articles\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/lcigaming.ca\/articles\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/lcigaming.ca\/articles\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/lcigaming.ca\/articles\/wp-json\/wp\/v2\/comments?post=299"}],"version-history":[{"count":2,"href":"https:\/\/lcigaming.ca\/articles\/wp-json\/wp\/v2\/posts\/299\/revisions"}],"predecessor-version":[{"id":307,"href":"https:\/\/lcigaming.ca\/articles\/wp-json\/wp\/v2\/posts\/299\/revisions\/307"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/lcigaming.ca\/articles\/wp-json\/wp\/v2\/media\/305"}],"wp:attachment":[{"href":"https:\/\/lcigaming.ca\/articles\/wp-json\/wp\/v2\/media?parent=299"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/lcigaming.ca\/articles\/wp-json\/wp\/v2\/categories?post=299"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/lcigaming.ca\/articles\/wp-json\/wp\/v2\/tags?post=299"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}