CSLA.NET 5.4.2
CSLA .NET is a software development framework that helps you build a reusable, maintainable object-oriented business layer for your app.
HttpPortalController.cs
Go to the documentation of this file.
1//-----------------------------------------------------------------------
2// <copyright file="HttpPortalController.cs" company="Marimer LLC">
3// Copyright (c) Marimer LLC. All rights reserved.
4// Website: https://cslanet.com
5// </copyright>
6// <summary>Exposes server-side DataPortal functionality</summary>
7//-----------------------------------------------------------------------
9using System;
10using System.IO;
11using System.Threading.Tasks;
12using System.Net.Http;
15
16#if NETSTANDARD2_0 || NET5_0 || NETCORE3_1
17
18using Microsoft.AspNetCore;
19using Microsoft.AspNetCore.Mvc;
20using System.Collections.Generic;
21
22#else
23using System.Web.Http;
24#endif
25
26namespace Csla.Server.Hosts
27{
32#if NETSTANDARD2_0 || NET5_0 || NETCORE3_1
33
34 public class HttpPortalController : Controller
35 {
41 public bool UseTextSerialization { get; set; } = false;
42
48 [HttpPost]
49 public virtual async Task PostAsync([FromQuery] string operation)
50 {
51 if (operation.Contains("/"))
52 {
53 var temp = operation.Split('/');
54 await PostAsync(temp[0], temp[1]);
55 }
56 else
57 {
58 if (UseTextSerialization)
59 await InvokeTextPortal(operation, Request.Body, Response.Body).ConfigureAwait(false);
60 else
61 await InvokePortal(operation, Request.Body, Response.Body).ConfigureAwait(false);
62 }
63 }
64
65 private static Dictionary<string, string> routingTagUrls = new Dictionary<string, string>();
66 private static HttpClient _client;
67
73 protected static Dictionary<string, string> RoutingTagUrls { get => routingTagUrls; set => routingTagUrls = value; }
74
79 protected int HttpClientTimeout { get; set; }
80
85 protected virtual HttpClient GetHttpClient()
86 {
87 if (_client == null)
88 {
89 _client = new HttpClient();
90 if (this.HttpClientTimeout > 0)
91 {
92 _client.Timeout = TimeSpan.FromMilliseconds(this.HttpClientTimeout);
93 }
94 }
95
96 return _client;
97 }
98
104 protected virtual async Task PostAsync(string operation, string routingTag)
105 {
106 if (RoutingTagUrls.TryGetValue(routingTag, out string route) && route != "localhost")
107 {
108 var httpRequest = new HttpRequestMessage(HttpMethod.Post, $"{route}?operation={operation}");
109 using (var buffer = new MemoryStream())
110 {
111 await Request.Body.CopyToAsync(buffer);
112 httpRequest.Content = new ByteArrayContent(buffer.ToArray());
113 }
114 var response = await GetHttpClient().SendAsync(httpRequest);
115 await response.Content.CopyToAsync(Response.Body);
116 }
117 else
118 {
119 await PostAsync(operation).ConfigureAwait(false);
120 }
121 }
122
123#elif MVC4
124 public class HttpPortalController : Controller
125 {
131 [HttpPost]
132 public virtual async Task<ActionResult> PostAsync(string operation)
133 {
134 var requestData = Request.BinaryRead(Request.TotalBytes);
135 var responseData = await InvokePortal(operation, requestData).ConfigureAwait(false);
136 Response.BinaryWrite(responseData);
137 return new EmptyResult();
138 }
139#else
140 public class HttpPortalController : ApiController
141 {
147 public virtual async Task<HttpResponseMessage> PostAsync(string operation)
148 {
149 var requestData = await Request.Content.ReadAsByteArrayAsync().ConfigureAwait(false);
150 var responseData = await InvokePortal(operation, requestData).ConfigureAwait(false);
151 var response = Request.CreateResponse();
152 response.Content = new ByteArrayContent(responseData);
153 return response;
154 }
155#endif
156
157 private HttpPortal _portal;
158
165 {
166 get
167 {
168 if (_portal == null)
169 _portal = new HttpPortal();
170 return _portal;
171 }
172 set { _portal = value; }
173 }
174
175#if NETSTANDARD2_0 || NET5_0 || NETCORE3_1
176
186 protected virtual void SetHttpResponseHeaders(Microsoft.AspNetCore.Http.HttpResponse response)
187 { }
188
189 private async Task InvokePortal(string operation, Stream requestStream, Stream responseStream)
190 {
191 var serializer = SerializationFormatterFactory.GetFormatter();
192 var result = new DataPortalResponse();
193 DataPortalErrorInfo errorData = null;
194 if (UseTextSerialization)
195 {
196 Response.Headers.Add("Content-type", "application/base64,text/plain");
197 }
198 else
199 {
200 Response.Headers.Add("Content-type", "application/octet-stream");
201 }
202 SetHttpResponseHeaders(Response);
203 try
204 {
205 var request = serializer.Deserialize(requestStream);
206 result = await CallPortal(operation, request);
207 }
208#pragma warning disable CA1031 // Do not catch general exception types
209 catch (Exception ex)
210 {
211 errorData = new DataPortalErrorInfo(ex);
212 }
213#pragma warning restore CA1031 // Do not catch general exception types
214 var portalResult = new DataPortalResponse { ErrorData = errorData, GlobalContext = result.GlobalContext, ObjectData = result.ObjectData };
215 serializer.Serialize(responseStream, portalResult);
216 }
217
218 private async Task InvokeTextPortal(string operation, Stream requestStream, Stream responseStream)
219 {
220 string requestString;
221 using (var reader = new StreamReader(requestStream))
222 requestString = await reader.ReadToEndAsync();
223 var requestArray = System.Convert.FromBase64String(requestString);
224 var requestBuffer = new MemoryStream(requestArray);
225
226 var serializer = SerializationFormatterFactory.GetFormatter();
227 var result = new DataPortalResponse();
228 DataPortalErrorInfo errorData = null;
229 try
230 {
231 var request = serializer.Deserialize(requestBuffer);
232 result = await CallPortal(operation, request);
233 }
234#pragma warning disable CA1031 // Do not catch general exception types
235 catch (Exception ex)
236 {
237 errorData = new DataPortalErrorInfo(ex);
238 }
239#pragma warning restore CA1031 // Do not catch general exception types
240 var portalResult = new DataPortalResponse { ErrorData = errorData, GlobalContext = result.GlobalContext, ObjectData = result.ObjectData };
241
242 var responseBuffer = new MemoryStream();
243 serializer.Serialize(responseBuffer, portalResult);
244 responseBuffer.Position = 0;
245 using var writer = new StreamWriter(responseStream)
246 {
247 AutoFlush = true
248 };
249 await writer.WriteAsync(System.Convert.ToBase64String(responseBuffer.ToArray()));
250 }
251
252#else
253 private async Task<byte[]> InvokePortal(string operation, byte[] data)
254 {
255 var result = new DataPortalResponse();
256 DataPortalErrorInfo errorData = null;
257 try
258 {
259 var buffer = new MemoryStream(data)
260 {
261 Position = 0
262 };
263 var request = SerializationFormatterFactory.GetFormatter().Deserialize(buffer.ToArray());
264 result = await CallPortal(operation, request);
265 }
266#pragma warning disable CA1031 // Do not catch general exception types
267 catch (Exception ex)
268 {
269 errorData = new DataPortalErrorInfo(ex);
270 }
271#pragma warning restore CA1031 // Do not catch general exception types
272 var portalResult = new DataPortalResponse { ErrorData = errorData, GlobalContext = result.GlobalContext, ObjectData = result.ObjectData };
273 var bytes = SerializationFormatterFactory.GetFormatter().Serialize(portalResult);
274 return bytes;
275 }
276#endif
277
278 private async Task<DataPortalResponse> CallPortal(string operation, object request)
279 {
280 var portal = Portal;
281 DataPortalResponse result = operation switch
282 {
283 "create" => await portal.Create((CriteriaRequest)request).ConfigureAwait(false),
284 "fetch" => await portal.Fetch((CriteriaRequest)request).ConfigureAwait(false),
285 "update" => await portal.Update((UpdateRequest)request).ConfigureAwait(false),
286 "delete" => await portal.Delete((CriteriaRequest)request).ConfigureAwait(false),
287 _ => throw new InvalidOperationException(operation),
288 };
289 return result;
290 }
291 }
292}
Message containing details about any server-side exception.
Response message for returning the results of a data portal call.
Request message for updating a business object.
Exposes server-side DataPortal functionality through HTTP request/response.
HttpPortal Portal
Gets or sets the HttpPortal implementation used to coordinate the data portal operations.
virtual async Task< HttpResponseMessage > PostAsync(string operation)
Entry point for all data portal operations.
Exposes server-side DataPortal functionality through HTTP request/response.
Definition: HttpPortal.cs:28