diff --git a/MTSC/Common/Http/Attributes/FromBodyAttribute.cs b/MTSC/Common/Http/Attributes/FromBodyAttribute.cs
index 4208a69..2e742a7 100644
--- a/MTSC/Common/Http/Attributes/FromBodyAttribute.cs
+++ b/MTSC/Common/Http/Attributes/FromBodyAttribute.cs
@@ -1,8 +1,12 @@
-using System;
+using MTSC.Common.Http.RoutingModules;
namespace MTSC.Common.Http.Attributes
{
- public sealed class FromBodyAttribute : Attribute
+ public sealed class FromBodyAttribute : StringRouteDataBindingBaseAttribute
{
+ public override string GetStringValue(HttpRouteBase route, RouteContext routeContext)
+ {
+ return routeContext.HttpRequest.BodyString;
+ }
}
}
diff --git a/MTSC/Common/Http/Attributes/FromHeadersAttribute.cs b/MTSC/Common/Http/Attributes/FromHeadersAttribute.cs
index 2506559..565ac20 100644
--- a/MTSC/Common/Http/Attributes/FromHeadersAttribute.cs
+++ b/MTSC/Common/Http/Attributes/FromHeadersAttribute.cs
@@ -1,8 +1,8 @@
-using System;
+using MTSC.Common.Http.RoutingModules;
namespace MTSC.Common.Http.Attributes
{
- public sealed class FromHeadersAttribute : Attribute
+ public sealed class FromHeadersAttribute : StringRouteDataBindingBaseAttribute
{
public string HeaderName { get; }
@@ -10,5 +10,15 @@ namespace MTSC.Common.Http.Attributes
{
this.HeaderName = headerName;
}
+
+ public override string GetStringValue(HttpRouteBase route, RouteContext routeContext)
+ {
+ if (routeContext.HttpRequest.Headers.ContainsHeader(this.HeaderName))
+ {
+ return routeContext.HttpRequest.Headers[this.HeaderName];
+ }
+
+ return null;
+ }
}
}
diff --git a/MTSC/Common/Http/Attributes/FromRouteContextResourcesAttribute.cs b/MTSC/Common/Http/Attributes/FromRouteContextResourcesAttribute.cs
index cf42db5..1707e09 100644
--- a/MTSC/Common/Http/Attributes/FromRouteContextResourcesAttribute.cs
+++ b/MTSC/Common/Http/Attributes/FromRouteContextResourcesAttribute.cs
@@ -1,8 +1,9 @@
-using System;
+using MTSC.Common.Http.RoutingModules;
+using System;
namespace MTSC.Common.Http.Attributes
{
- public sealed class FromRouteContextResourcesAttribute : Attribute
+ public sealed class FromRouteContextResourcesAttribute : RouteDataBindingBaseAttribute
{
public string ResourceKey { get; }
@@ -10,5 +11,15 @@ namespace MTSC.Common.Http.Attributes
{
this.ResourceKey = resourceKey;
}
+
+ public override object DataBind(HttpRouteBase route, RouteContext routeContext, Type propertyType)
+ {
+ if (routeContext.Resources.TryGetValue(this.ResourceKey, out var resource))
+ {
+ return resource;
+ }
+
+ return null;
+ }
}
}
diff --git a/MTSC/Common/Http/Attributes/FromUrlAttribute.cs b/MTSC/Common/Http/Attributes/FromUrlAttribute.cs
index ba8a563..1345ff7 100644
--- a/MTSC/Common/Http/Attributes/FromUrlAttribute.cs
+++ b/MTSC/Common/Http/Attributes/FromUrlAttribute.cs
@@ -1,8 +1,8 @@
-using System;
+using MTSC.Common.Http.RoutingModules;
namespace MTSC.Common.Http.Attributes
{
- public class FromUrlAttribute : Attribute
+ public class FromUrlAttribute : StringRouteDataBindingBaseAttribute
{
public string Placeholder { get; }
@@ -10,5 +10,15 @@ namespace MTSC.Common.Http.Attributes
{
this.Placeholder = placeholder;
}
+
+ public override string GetStringValue(HttpRouteBase route, RouteContext routeContext)
+ {
+ if (routeContext.UrlValues.TryGetValue(this.Placeholder, out var value))
+ {
+ return value;
+ }
+
+ return null;
+ }
}
}
diff --git a/MTSC/Common/Http/Attributes/RouteDataBindingBaseAttribute.cs b/MTSC/Common/Http/Attributes/RouteDataBindingBaseAttribute.cs
new file mode 100644
index 0000000..7357d07
--- /dev/null
+++ b/MTSC/Common/Http/Attributes/RouteDataBindingBaseAttribute.cs
@@ -0,0 +1,19 @@
+using MTSC.Common.Http.RoutingModules;
+using System;
+
+namespace MTSC.Common.Http.Attributes
+{
+ public abstract class RouteDataBindingBaseAttribute : Attribute
+ {
+ ///
+ /// Perform the data binding logic and return the bindable value.
+ /// This value will be attached to the decorated property.
+ /// The value can be
+ ///
+ /// object.
+ /// for the current request.
+ /// of property to be binded.
+ /// Object to be binded to the decorated property.
+ public abstract object DataBind(HttpRouteBase route, RouteContext routeContext, Type propertyType);
+ }
+}
diff --git a/MTSC/Common/Http/Attributes/StringRouteDataBindingBaseAttribute.cs b/MTSC/Common/Http/Attributes/StringRouteDataBindingBaseAttribute.cs
new file mode 100644
index 0000000..e674316
--- /dev/null
+++ b/MTSC/Common/Http/Attributes/StringRouteDataBindingBaseAttribute.cs
@@ -0,0 +1,63 @@
+using MTSC.Common.Http.RoutingModules;
+using Newtonsoft.Json;
+using System;
+using System.ComponentModel;
+
+namespace MTSC.Common.Http.Attributes
+{
+ public abstract class StringRouteDataBindingBaseAttribute : RouteDataBindingBaseAttribute
+ {
+ public override sealed object DataBind(HttpRouteBase route, RouteContext routeContext, Type propertyType)
+ {
+ var stringValue = this.GetStringValue(route, routeContext);
+ return BindValue(propertyType, stringValue);
+ }
+
+ ///
+ /// Returns a string value that will later be converted to the decorated property .
+ /// Conversion tries as well as if the property is not .
+ ///
+ /// route.
+ /// of the request.
+ /// A string value to be converted to the decorated property .
+ public abstract string GetStringValue(HttpRouteBase route, RouteContext routeContext);
+
+ private object BindValue(Type propertyType, string value)
+ {
+ object finalValue = null;
+ if (propertyType == typeof(string))
+ {
+ finalValue = value;
+ }
+ else if (this.TryConvertWithTypeConverter(propertyType, value, out var typeConvertedValue))
+ {
+ finalValue = typeConvertedValue;
+ }
+ else if (this.TryConvertWithJsonConvert(propertyType, value, out var jsonConvertedValue))
+ {
+ finalValue = jsonConvertedValue;
+ }
+
+ return finalValue;
+ }
+
+ private bool TryConvertWithTypeConverter(Type propertyType, string value, out object convertedValue)
+ {
+ var typeConverter = TypeDescriptor.GetConverter(propertyType);
+ if (typeConverter.CanConvertFrom(typeof(string)))
+ {
+ convertedValue = typeConverter.ConvertFrom(value);
+ return true;
+ }
+
+ convertedValue = null;
+ return false;
+ }
+
+ private bool TryConvertWithJsonConvert(Type propertyType, string value, out object convertedValue)
+ {
+ convertedValue = JsonConvert.DeserializeObject(value, propertyType);
+ return true;
+ }
+ }
+}
diff --git a/MTSC/Common/Http/RouteContext.cs b/MTSC/Common/Http/RouteContext.cs
index 2f66ad8..a2a2a8f 100644
--- a/MTSC/Common/Http/RouteContext.cs
+++ b/MTSC/Common/Http/RouteContext.cs
@@ -9,18 +9,22 @@ namespace MTSC.Common.Http
public Server Server { get; }
public HttpRequest HttpRequest { get; }
public ClientData Client { get; }
+ public Dictionary UrlValues { get; }
public HttpResponse HttpResponse { get; set; }
public CancellationToken CancelRequest => this.Client.CancellationToken;
public Dictionary Resources { get; set; } = new();
+
public RouteContext(
Server server,
HttpRequest httpRequest,
- ClientData clientData)
+ ClientData clientData,
+ Dictionary urlValues)
{
this.Server = server;
this.HttpRequest = httpRequest;
this.Client = clientData;
+ this.UrlValues = urlValues;
}
}
}
diff --git a/MTSC/Exceptions/DataBindingException.cs b/MTSC/Exceptions/DataBindingException.cs
index 61dfabe..d0db95b 100644
--- a/MTSC/Exceptions/DataBindingException.cs
+++ b/MTSC/Exceptions/DataBindingException.cs
@@ -1,24 +1,31 @@
-using System;
+using MTSC.Common.Http;
+using MTSC.Common.Http.Attributes;
+using MTSC.Common.Http.RoutingModules;
+using System;
+using System.Reflection;
using System.Runtime.Serialization;
namespace MTSC.Exceptions
{
- public abstract class DataBindingException : Exception
+ public sealed class DataBindingException : Exception
{
- protected DataBindingException()
- {
- }
+ public HttpRouteBase Route { get; }
+ public RouteContext RouteContext { get; }
+ public RouteDataBindingBaseAttribute RouteDataBindingBaseAttribute { get; }
+ public PropertyInfo PropertyInfo { get; }
- protected DataBindingException(string message) : base(message)
- {
- }
-
- protected DataBindingException(string message, Exception innerException) : base(message, innerException)
- {
- }
-
- protected DataBindingException(SerializationInfo info, StreamingContext context) : base(info, context)
+ public DataBindingException(
+ Exception innerException,
+ HttpRouteBase route,
+ RouteContext routeContext,
+ RouteDataBindingBaseAttribute routeDataBindingBaseAttribute,
+ PropertyInfo propertyInfo)
+ : base("Exception occurred during data binding. Check inner exception for details", innerException)
{
+ this.Route = route;
+ this.RouteContext = routeContext;
+ this.RouteDataBindingBaseAttribute = routeDataBindingBaseAttribute;
+ this.PropertyInfo = propertyInfo;
}
}
}
diff --git a/MTSC/Exceptions/FromBodyDataBindingException.cs b/MTSC/Exceptions/FromBodyDataBindingException.cs
deleted file mode 100644
index 2d598e1..0000000
--- a/MTSC/Exceptions/FromBodyDataBindingException.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-using System;
-
-namespace MTSC.Exceptions
-{
- public sealed class FromBodyDataBindingException : Exception
- {
- public Type PropertyType { get; }
- public string Value { get; }
-
- public FromBodyDataBindingException(
- Exception innerException,
- Type propertyType,
- string value)
- : base("Encountered exception when binding data from body", innerException)
- {
- this.PropertyType = propertyType;
- this.Value = value;
- }
- }
-}
diff --git a/MTSC/Exceptions/FromHeadersDataBindingException.cs b/MTSC/Exceptions/FromHeadersDataBindingException.cs
deleted file mode 100644
index 7ffcc25..0000000
--- a/MTSC/Exceptions/FromHeadersDataBindingException.cs
+++ /dev/null
@@ -1,23 +0,0 @@
-using System;
-
-namespace MTSC.Exceptions
-{
- public sealed class FromHeadersDataBindingException : Exception
- {
- public Type PropertyType { get; }
- public string Header { get; }
- public string Value { get; }
-
- public FromHeadersDataBindingException(
- Exception innerException,
- Type propertyType,
- string header,
- string value)
- : base("Encountered exception when binding data from headers", innerException)
- {
- this.PropertyType = propertyType;
- this.Header = header;
- this.Value = value;
- }
- }
-}
diff --git a/MTSC/Exceptions/FromRouteContextResourcesDataBindingException.cs b/MTSC/Exceptions/FromRouteContextResourcesDataBindingException.cs
deleted file mode 100644
index cb5c984..0000000
--- a/MTSC/Exceptions/FromRouteContextResourcesDataBindingException.cs
+++ /dev/null
@@ -1,24 +0,0 @@
-using System;
-using MTSC.Common.Http;
-
-namespace MTSC.Exceptions
-{
- public sealed class FromRouteContextResourcesDataBindingException : Exception
- {
- public Type PropertyType { get; }
- public string Key { get; }
- public RouteContext RouteContext { get; }
-
- public FromRouteContextResourcesDataBindingException(
- Exception innerException,
- Type propertyType,
- string key,
- RouteContext routeContext)
- : base("Encountered exception when binding data from route context resources", innerException)
- {
- this.PropertyType = propertyType;
- this.Key = key;
- this.RouteContext = routeContext;
- }
- }
-}
diff --git a/MTSC/Exceptions/FromUrlDataBindingException.cs b/MTSC/Exceptions/FromUrlDataBindingException.cs
deleted file mode 100644
index ffe3a32..0000000
--- a/MTSC/Exceptions/FromUrlDataBindingException.cs
+++ /dev/null
@@ -1,23 +0,0 @@
-using System;
-
-namespace MTSC.Exceptions
-{
- public sealed class FromUrlDataBindingException : DataBindingException
- {
- public Type PropertyType { get; }
- public string Placeholder { get; }
- public string Value { get; }
-
- public FromUrlDataBindingException(
- Exception innerException,
- Type propertyType,
- string placeHolder,
- string value)
- : base("Encountered exception when binding data from url", innerException)
- {
- this.PropertyType = propertyType;
- this.Placeholder = placeHolder;
- this.Value = value;
- }
- }
-}
diff --git a/MTSC/MTSC.csproj b/MTSC/MTSC.csproj
index 6219e01..abb42b2 100644
--- a/MTSC/MTSC.csproj
+++ b/MTSC/MTSC.csproj
@@ -5,13 +5,13 @@
net48;netstandard2.0;netcoreapp3.1;net5.0;net6.0
- 5.1.6
+ 5.2.0
latest
Alexandru-Victor Macocian
MTSC
Modular TCP Server and Client
- 5.1.6.0
- 5.1.6.0
+ 5.2.0.0
+ 5.2.0.0
true
AnyCPU;x64
https://github.com/AlexMacocian/MTSC
diff --git a/MTSC/ServerSide/Handlers/HttpRoutingHandler.cs b/MTSC/ServerSide/Handlers/HttpRoutingHandler.cs
index 7e15a3a..1d6d820 100644
--- a/MTSC/ServerSide/Handlers/HttpRoutingHandler.cs
+++ b/MTSC/ServerSide/Handlers/HttpRoutingHandler.cs
@@ -229,7 +229,11 @@ namespace MTSC.ServerSide.Handlers
httpLogger.LogRequest(server, this, client, request);
}
- var routeContext = new RouteContext(server, request, client);
+ var routeContext = new RouteContext(
+ server,
+ request,
+ client,
+ urlValues.ToDictionary(u => u.Placeholder, u => u.Value));
foreach(var filterType in filterTypes)
{
var filter = server.ServiceManager.GetService(filterType) as RouteFilterAttribute;
@@ -254,7 +258,7 @@ namespace MTSC.ServerSide.Handlers
}
- this.RouteHandleRequest(module, routeContext, filterTypes, urlValues).ContinueWith(task =>
+ this.RouteHandleRequest(module, routeContext, filterTypes).ContinueWith(task =>
{
this.QueueResponse(client, task.Result);
});
@@ -368,12 +372,11 @@ namespace MTSC.ServerSide.Handlers
private async Task RouteHandleRequest(
HttpRouteBase httpRouteBase,
RouteContext routeContext,
- List filterTypes,
- List urlValues)
+ List filterTypes)
{
try
{
- this.SetModuleProperties(httpRouteBase, routeContext, urlValues);
+ this.SetModuleProperties(httpRouteBase, routeContext);
var response = await httpRouteBase.CallHandleRequest(routeContext.HttpRequest);
routeContext.HttpResponse = response;
foreach (var filterType in filterTypes)
@@ -440,7 +443,7 @@ namespace MTSC.ServerSide.Handlers
{
foreach (var attribute in property.GetCustomAttributes(true))
{
- if (attribute is FromUrlAttribute or FromBodyAttribute or FromHeadersAttribute)
+ if (attribute is RouteDataBindingBaseAttribute)
{
propertyAndAttributesList.Add(((Attribute)attribute, property));
}
@@ -470,99 +473,29 @@ namespace MTSC.ServerSide.Handlers
return false;
}
- private void SetModuleProperties(HttpRouteBase module, RouteContext routeContext, List urlValues)
+ private void SetModuleProperties(HttpRouteBase module, RouteContext routeContext)
{
- var propertiesAndAttributes = this.routePropertyCache[module.GetType()];
foreach ((var attribute, var propertyInfo) in this.routePropertyCache[module.GetType()])
{
- if (attribute is FromUrlAttribute fromUrlAttribute)
- {
- var maybeValue = urlValues.Where(val => val.Placeholder == fromUrlAttribute.Placeholder).FirstOrDefault();
- if (maybeValue is not null)
- {
- try
- {
- this.TryAssignValue(propertyInfo, maybeValue.Value, module);
- }
- catch (Exception ex)
- {
- if (this.ThrowOnBindingErrors)
- {
- throw new FromUrlDataBindingException(ex, propertyInfo.PropertyType, maybeValue.Placeholder, maybeValue.Value);
- }
- }
- }
- }
- else if (attribute is FromBodyAttribute)
+ if (attribute is RouteDataBindingBaseAttribute routeDataBindingBaseAttribute)
{
try
{
- this.TryAssignValue(propertyInfo, routeContext.HttpRequest.BodyString, module);
+ var value = routeDataBindingBaseAttribute.DataBind(module, routeContext, propertyInfo.PropertyType);
+ SetPropertyValue(propertyInfo, value, module);
}
catch (Exception ex)
{
if (this.ThrowOnBindingErrors)
{
- throw new FromBodyDataBindingException(ex, propertyInfo.PropertyType, routeContext.HttpRequest.BodyString);
- }
- }
- }
- else if (attribute is FromHeadersAttribute fromHeadersAttribute)
- {
- var maybeValue = routeContext.HttpRequest.Headers.Where(kvp => kvp.Key == fromHeadersAttribute.HeaderName).FirstOrDefault();
- if (maybeValue.Value is not null)
- {
- try
- {
- this.TryAssignValue(propertyInfo, maybeValue.Value, module);
- }
- catch (Exception ex)
- {
- if (this.ThrowOnBindingErrors)
- {
- throw new FromHeadersDataBindingException(ex, propertyInfo.PropertyType, fromHeadersAttribute.HeaderName, maybeValue.Value);
- }
- }
- }
- }
- else if (attribute is FromRouteContextResourcesAttribute fromRouteContextResourcesAttribute)
- {
- if (routeContext.Resources.TryGetValue(fromRouteContextResourcesAttribute.ResourceKey, out var value))
- {
- try
- {
- SetPropertyValue(propertyInfo, value, module);
- }
- catch (Exception ex)
- {
- if (this.ThrowOnBindingErrors)
- {
- throw new FromRouteContextResourcesDataBindingException(ex, propertyInfo.PropertyType, fromRouteContextResourcesAttribute.ResourceKey, routeContext);
- }
+ throw new DataBindingException(ex, module, routeContext, routeDataBindingBaseAttribute, propertyInfo);
}
}
}
}
}
- private void TryAssignValue(PropertyInfo propertyInfo, string value, HttpRouteBase module)
- {
- object finalValue = null;
- if (propertyInfo.PropertyType == typeof(string))
- {
- finalValue = value;
- }
- else if (this.TryConvertWithTypeConverter(propertyInfo, value, out var typeConvertedValue))
- {
- finalValue = typeConvertedValue;
- }
- else if (this.TryConvertWithJsonConvert(propertyInfo, value, out var jsonConvertedValue))
- {
- finalValue = jsonConvertedValue;
- }
-
- SetPropertyValue(propertyInfo, finalValue, module);
- }
+
private static void SetPropertyValue(PropertyInfo propertyInfo, object value, HttpRouteBase module)
{
@@ -577,47 +510,7 @@ namespace MTSC.ServerSide.Handlers
}
}
- private bool TryConvertWithTypeConverter(PropertyInfo propertyInfo, string value, out object convertedValue)
- {
- try
- {
- var typeConverter = TypeDescriptor.GetConverter(propertyInfo.PropertyType);
- if (typeConverter.CanConvertFrom(typeof(string)))
- {
- convertedValue = typeConverter.ConvertFrom(value);
- return true;
- }
- }
- catch
- {
- if (this.ThrowOnBindingErrors is true)
- {
- throw;
- }
- }
-
- convertedValue = null;
- return false;
- }
- private bool TryConvertWithJsonConvert(PropertyInfo propertyInfo, string value, out object convertedValue)
- {
- try
- {
- convertedValue = JsonConvert.DeserializeObject(value, propertyInfo.PropertyType);
- return true;
- }
- catch
- {
- if (this.ThrowOnBindingErrors is true)
- {
- throw;
- }
- }
-
- convertedValue = null;
- return false;
- }
private static HttpResponse NotFound404 => new()
{