CSLA.NET 6.0.0
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_OR_GREATER || NETCOREAPP3_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_OR_GREATER || NETCOREAPP3_1
33
34 public class HttpPortalController : Controller
35 {
36 private ApplicationContext ApplicationContext { get; set; }
37
42 public HttpPortalController(ApplicationContext applicationContext)
43 {
44 ApplicationContext = applicationContext;
45 }
46
52 public bool UseTextSerialization { get; set; } = false;
53
59 [HttpPost]
60 public virtual async Task PostAsync([FromQuery] string operation)
61 {
62 if (operation.Contains("/"))
63 {
64 var temp = operation.Split('/');
65 await PostAsync(temp[0], temp[1]);
66 }
67 else
68 {
69 if (UseTextSerialization)
70 await InvokeTextPortal(operation, Request.Body, Response.Body).ConfigureAwait(false);
71 else
72 await InvokePortal(operation, Request.Body, Response.Body).ConfigureAwait(false);
73 }
74 }
75
76 private static Dictionary<string, string> routingTagUrls = new Dictionary<string, string>();
77 private static HttpClient _client;
78
84 protected static Dictionary<string, string> RoutingTagUrls { get => routingTagUrls; set => routingTagUrls = value; }
85
90 protected int HttpClientTimeout { get; set; }
91
96 protected virtual HttpClient GetHttpClient()
97 {
98 if (_client == null)
99 {
100 _client = new HttpClient();
101 if (this.HttpClientTimeout > 0)
102 {
103 _client.Timeout = TimeSpan.FromMilliseconds(this.HttpClientTimeout);
104 }
105 }
106
107 return _client;
108 }
109
115 protected virtual async Task PostAsync(string operation, string routingTag)
116 {
117 if (RoutingTagUrls.TryGetValue(routingTag, out string route) && route != "localhost")
118 {
119 var httpRequest = new HttpRequestMessage(HttpMethod.Post, $"{route}?operation={operation}");
120 using (var buffer = new MemoryStream())
121 {
122 await Request.Body.CopyToAsync(buffer);
123 httpRequest.Content = new ByteArrayContent(buffer.ToArray());
124 }
125 var response = await GetHttpClient().SendAsync(httpRequest);
126 await response.Content.CopyToAsync(Response.Body);
127 }
128 else
129 {
130 await PostAsync(operation).ConfigureAwait(false);
131 }
132 }
133#else // NET462 and MVC5
134 public class HttpPortalController : ApiController
135 {
136 private ApplicationContext ApplicationContext { get; set; }
137
142 public HttpPortalController(ApplicationContext applicationContext)
143 {
144 ApplicationContext = applicationContext;
145 }
146
152 public virtual async Task<HttpResponseMessage> PostAsync(string operation)
153 {
154 var requestData = await Request.Content.ReadAsByteArrayAsync().ConfigureAwait(false);
155 var responseData = await InvokePortal(operation, requestData).ConfigureAwait(false);
156 var response = Request.CreateResponse();
157 response.Content = new ByteArrayContent(responseData);
158 return response;
159 }
160#endif
161
162 private HttpPortal _portal;
163
170 {
171 get
172 {
173 if (_portal == null)
175 return _portal;
176 }
177 set { _portal = value; }
178 }
179
180#if NETSTANDARD2_0 || NET5_0_OR_GREATER || NETCOREAPP3_1
181
191 protected virtual void SetHttpResponseHeaders(Microsoft.AspNetCore.Http.HttpResponse response)
192 { }
193
194 private async Task InvokePortal(string operation, Stream requestStream, Stream responseStream)
195 {
196 var serializer = SerializationFormatterFactory.GetFormatter(ApplicationContext);
198 DataPortalErrorInfo errorData = null;
199 if (UseTextSerialization)
200 {
201 Response.Headers.Add("Content-type", "application/base64,text/plain");
202 }
203 else
204 {
205 Response.Headers.Add("Content-type", "application/octet-stream");
206 }
207 SetHttpResponseHeaders(Response);
208 try
209 {
210 var request = serializer.Deserialize(requestStream);
211 result = await CallPortal(operation, request);
212 }
213#pragma warning disable CA1031 // Do not catch general exception types
214 catch (Exception ex)
215 {
216 errorData = ApplicationContext.CreateInstance<DataPortalErrorInfo>(ApplicationContext, ex);
217 }
218#pragma warning restore CA1031 // Do not catch general exception types
219 var portalResult = ApplicationContext.CreateInstanceDI<DataPortalResponse>();
220 portalResult.ErrorData = errorData;
221 portalResult.ObjectData = result.ObjectData;
222 serializer.Serialize(responseStream, portalResult);
223 }
224
225 private async Task InvokeTextPortal(string operation, Stream requestStream, Stream responseStream)
226 {
227 string requestString;
228 using (var reader = new StreamReader(requestStream))
229 requestString = await reader.ReadToEndAsync();
230 var requestArray = System.Convert.FromBase64String(requestString);
231 var requestBuffer = new MemoryStream(requestArray);
232
233 var serializer = SerializationFormatterFactory.GetFormatter(ApplicationContext);
234 var result = ApplicationContext.CreateInstanceDI<DataPortalResponse>();
235 DataPortalErrorInfo errorData = null;
236 try
237 {
238 var request = serializer.Deserialize(requestBuffer);
239 result = await CallPortal(operation, request);
240 }
241#pragma warning disable CA1031 // Do not catch general exception types
242 catch (Exception ex)
243 {
244 errorData = ApplicationContext.CreateInstance<DataPortalErrorInfo>(ApplicationContext, ex);
245 }
246#pragma warning restore CA1031 // Do not catch general exception types
247 var portalResult = ApplicationContext.CreateInstanceDI<DataPortalResponse>();
248 portalResult.ErrorData = errorData;
249 portalResult.ObjectData = result.ObjectData;
250
251 var responseBuffer = new MemoryStream();
252 serializer.Serialize(responseBuffer, portalResult);
253 responseBuffer.Position = 0;
254 using var writer = new StreamWriter(responseStream)
255 {
256 AutoFlush = true
257 };
258 await writer.WriteAsync(System.Convert.ToBase64String(responseBuffer.ToArray()));
259 }
260
261#else
262 private async Task<byte[]> InvokePortal(string operation, byte[] data)
263 {
264 var result = ApplicationContext.CreateInstance<DataPortalResponse>();
265 DataPortalErrorInfo errorData = null;
266 try
267 {
268 var buffer = new MemoryStream(data)
269 {
270 Position = 0
271 };
272 var request = SerializationFormatterFactory.GetFormatter(ApplicationContext).Deserialize(buffer.ToArray());
273 result = await CallPortal(operation, request);
274 }
275#pragma warning disable CA1031 // Do not catch general exception types
276 catch (Exception ex)
277 {
278 errorData = ApplicationContext.CreateInstance<DataPortalErrorInfo>(ApplicationContext, ex);
279 }
280#pragma warning restore CA1031 // Do not catch general exception types
281 var portalResult = ApplicationContext.CreateInstance<DataPortalResponse>();
282 portalResult.ErrorData = errorData;
283 portalResult.ObjectData = result.ObjectData;
284 var bytes = SerializationFormatterFactory.GetFormatter(ApplicationContext).Serialize(portalResult);
285 return bytes;
286 }
287#endif
288
289 private async Task<DataPortalResponse> CallPortal(string operation, object request)
290 {
291 var portal = Portal;
292 DataPortalResponse result = operation switch
293 {
294 "create" => await portal.Create((CriteriaRequest)request).ConfigureAwait(false),
295 "fetch" => await portal.Fetch((CriteriaRequest)request).ConfigureAwait(false),
296 "update" => await portal.Update((UpdateRequest)request).ConfigureAwait(false),
297 "delete" => await portal.Delete((CriteriaRequest)request).ConfigureAwait(false),
298 _ => throw new InvalidOperationException(operation),
299 };
300 return result;
301 }
302 }
303}
Provides consistent context information between the client and server DataPortal objects.
object CreateInstanceDI(Type objectType, params object[] parameters)
Creates an object using 'Activator.CreateInstance' using service provider (if one is available) to po...
Message sent to the WCF data portal.
Message containing details about any server-side exception.
Response message for returning the results of a data portal call.
DataPortalErrorInfo ErrorData
Server-side exception data if an exception occurred on the server.
Request message for updating a business object.
Exposes server-side DataPortal functionality through HTTP request/response.
HttpPortalController(ApplicationContext applicationContext)
Creates an instance of the type.
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