Skip to content

Commit 195b8c5

Browse files
author
MuhammadUmarqulov
committed
FromBody Attribute is implemented.
1 parent c4e4949 commit 195b8c5

File tree

7 files changed

+267
-20
lines changed

7 files changed

+267
-20
lines changed

Tigernet.Samples.RestApi/Resters/UsersRester.cs

+4-10
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using Tigernet.Hosting.Actions;
22
using Tigernet.Hosting.Attributes.HttpMethods;
3+
using Tigernet.Hosting.Attributes.RequestContents;
34
using Tigernet.Hosting.Attributes.Resters;
45
using Tigernet.Hosting.Models.Query;
56
using Tigernet.Samples.RestApi.Clevers.Interfaces;
@@ -24,22 +25,15 @@ public async ValueTask<object> GetByFilter(EntityQueryOptions<User> model)
2425
}
2526

2627
[Getter]
27-
public async ValueTask<object> Get()
28+
public async ValueTask<object> Get([FromBody] int id)
2829
{
29-
var result = await userClever.GetByIdAsync(1);
30+
var result = await userClever.GetByIdAsync(id);
3031
return Ok(result);
3132
}
3233

3334
[Poster("/new")]
34-
public object Add()
35+
public object Add([FromBody] User user)
3536
{
36-
User user = new User()
37-
{
38-
Id = 7,
39-
Name = "Ikrom",
40-
Age = 28
41-
};
42-
4337
return Ok(userClever.Add(user));
4438
}
4539

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
using Tigernet.Hosting.Enums;
2+
3+
namespace Tigernet.Hosting.Attributes.RequestContents;
4+
5+
[AttributeUsage(AttributeTargets.Parameter)]
6+
public abstract class RequestContentAttribute : Attribute
7+
{
8+
/// <summary>
9+
/// Request coming data section can be multiple
10+
/// </summary>
11+
public abstract bool CanMultiple { get; protected set; }
12+
13+
public abstract Transfer DataMapSource { get; protected set; }
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
using Tigernet.Hosting.Enums;
2+
3+
namespace Tigernet.Hosting.Attributes.RequestContents;
4+
5+
public class FromBodyAttribute : RequestContentAttribute
6+
{
7+
/// <inheritdoc />
8+
public override bool CanMultiple { get; protected set; } = false;
9+
10+
public override Transfer DataMapSource { get; protected set; } = Transfer.FromBody;
11+
}
+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
namespace Tigernet.Hosting.Enums;
2+
3+
public enum Transfer
4+
{
5+
FromBody,
6+
FromHeader,
7+
FromRoute,
8+
FromQuery,
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
using System.Net;
2+
using System.Text;
3+
using System.Text.Json;
4+
using Tigernet.Hosting.Enums;
5+
6+
namespace Tigernet.Hosting.Extensions;
7+
8+
/// <summary>
9+
/// Extension class for HttpListenerRequest that provides methods for retrieving data from different parts of the request.
10+
/// </summary>
11+
internal static class RequestListenerExtension
12+
{
13+
internal static object? GetInjectingRequestData(
14+
this HttpListenerRequest request,
15+
Type returnType, Transfer transfer,
16+
string selector = null!)
17+
{
18+
return transfer switch
19+
{
20+
Transfer.FromBody => request.GetDataFromRequestBody(returnType),
21+
Transfer.FromHeader => request.GetDataFromRequestHeader(selector, returnType),
22+
Transfer.FromRoute => request.GetDataFromRequestRoute(selector, returnType),
23+
Transfer.FromQuery => request.GetDataFromRequestQuery(returnType),
24+
_ => default
25+
};
26+
}
27+
28+
internal static T? GetInjectingRequestData<T>(
29+
this HttpListenerRequest request, Transfer transfer,
30+
string selector = null!)
31+
{
32+
return transfer switch
33+
{
34+
Transfer.FromBody => request.GetDataFromRequestBody<T>(),
35+
Transfer.FromHeader => request.GetDataFromRequestHeader<T>(selector),
36+
Transfer.FromRoute => request.GetDataFromRequestRoute<T>(selector),
37+
Transfer.FromQuery => request.GetDataFromRequestQuery<T>(),
38+
_ => default
39+
};
40+
}
41+
42+
#region Private methods
43+
44+
#region Map from request body
45+
46+
/// <summary>
47+
/// Retrieves data from the request body and returns it as the specified type.
48+
/// </summary>
49+
/// <typeparam name="T">The type to return the data as.</typeparam>
50+
/// <param name="request">The HttpListenerRequest to extract data from.</param>
51+
/// <returns>The data extracted from the request body as the specified type.</returns>
52+
private static T? GetDataFromRequestBody<T>(this HttpListenerRequest request)
53+
{
54+
using Stream bodyStream = request.InputStream;
55+
// Determine the encoding and content type of the request
56+
Encoding encoding = request.ContentEncoding;
57+
58+
// Read the data from the request body
59+
using StreamReader reader = new StreamReader(bodyStream, encoding);
60+
string requestBody = reader.ReadToEnd();
61+
62+
if (requestBody != String.Empty)
63+
return JsonSerializer.Deserialize<T>(requestBody);
64+
65+
throw new NullReferenceException("In request body value is not given. ");
66+
}
67+
68+
/// <summary>
69+
/// Retrieves data from the request body and returns it as the specified type.
70+
/// </summary>
71+
/// <param name="request">The HttpListenerRequest to extract data from.</param>
72+
/// <param name="returnType">Returned type of the data.</param>
73+
/// <returns>The data extracted from the request body as the specified type.</returns>
74+
private static object? GetDataFromRequestBody(this HttpListenerRequest request, Type returnType)
75+
{
76+
using Stream bodyStream = request.InputStream;
77+
// Determine the encoding and content type of the request
78+
Encoding encoding = request.ContentEncoding;
79+
80+
// Read the data from the request body
81+
using StreamReader reader = new StreamReader(bodyStream, encoding);
82+
string requestBody = reader.ReadToEnd();
83+
84+
if (requestBody != String.Empty)
85+
return JsonSerializer.Deserialize(requestBody, returnType);
86+
87+
throw new NullReferenceException("In request body value is not given. ");
88+
}
89+
90+
#endregion
91+
92+
#region Map from request header
93+
94+
/// <summary>
95+
/// Retrieves data from the specified header in the request and returns it as the specified type.
96+
/// </summary>
97+
/// <typeparam name="T">The type to return the data as.</typeparam>
98+
/// <param name="request">The HttpListenerRequest to extract data from.</param>
99+
/// <param name="key">The key of the header to extract data from.</param>
100+
/// <returns>The data extracted from the specified header as the specified type.</returns>
101+
private static T? GetDataFromRequestHeader<T>(
102+
this HttpListenerRequest request,
103+
string key)
104+
{
105+
var header = request.Headers.Get(key);
106+
if (header != null)
107+
return JsonSerializer.Deserialize<T>(header);
108+
109+
throw new NullReferenceException($"In request header with given key '{key}' is not value is not detected");
110+
}
111+
112+
/// <summary>
113+
/// Retrieves data from the specified header in the request and returns it as the specified type.
114+
/// </summary>
115+
/// <param name="request">The HttpListenerRequest to extract data from.</param>
116+
/// <param name="key">The key of the header to extract data from.</param>
117+
/// <param name="returnType">return type of the request data</param>
118+
/// <returns>The data extracted from the specified header as the specified type.</returns>
119+
private static object? GetDataFromRequestHeader(
120+
this HttpListenerRequest request,
121+
string key, Type returnType)
122+
{
123+
string? header = request.Headers.Get(key);
124+
return JsonSerializer.Deserialize(header ?? "", returnType);
125+
}
126+
127+
#endregion
128+
129+
#region Map from request route
130+
131+
/// <summary>
132+
/// Retrieves data from the specified route in the request and returns it as the specified type.
133+
/// </summary>
134+
/// <param name="request">The HttpListenerRequest to extract data from.</param>
135+
/// <param name="key">The key of the route to extract data from.</param>
136+
/// <returns>The data extracted from the specified route as the specified type.</returns>
137+
private static T? GetDataFromRequestRoute<T>(
138+
this HttpListenerRequest request,
139+
string key)
140+
{
141+
var routeValue = request.Url?.Segments[^1];
142+
return JsonSerializer.Deserialize<T>(routeValue ?? "");
143+
}
144+
145+
/// <summary>
146+
/// Retrieves data from the specified route in the request and returns it as the specified type.
147+
/// </summary>
148+
/// <param name="request">The HttpListenerRequest to extract data from.</param>
149+
/// <param name="key">The key of the route to extract data from.</param>
150+
/// <param name="returnType">return type of the request data value</param>
151+
/// <returns>The data extracted from the specified route as the specified type.</returns>
152+
private static object? GetDataFromRequestRoute(
153+
this HttpListenerRequest request,
154+
string key, Type returnType)
155+
{
156+
var routeValue = request.Url?.Segments[^1];
157+
return JsonSerializer.Deserialize(routeValue ?? "", returnType);
158+
}
159+
160+
#endregion
161+
162+
#region Map from request query
163+
164+
/// <summary>
165+
/// Retrieves data from the request query and returns it as the specified type.
166+
/// </summary>
167+
/// <typeparam name="T">The type to return the data as.</typeparam>
168+
/// <param name="request">The HttpListenerRequest to extract data from.</param>
169+
/// <returns>The data extracted from the request query as the specified type.</returns>
170+
private static T? GetDataFromRequestQuery<T>(
171+
this HttpListenerRequest request)
172+
{
173+
var queryValue = request.QueryString.ToString();
174+
return JsonSerializer.Deserialize<T>(queryValue ?? "");
175+
}
176+
177+
/// <summary>
178+
/// Retrieves data from the request query and returns it as the specified type.
179+
/// </summary>
180+
/// <param name="request">The HttpListenerRequest to extract data from.</param>
181+
/// <param name="returnType">returned type of the request coming data</param>
182+
/// <returns>The data extracted from the request query as the specified type.</returns>
183+
private static object? GetDataFromRequestQuery(
184+
this HttpListenerRequest request,
185+
Type returnType)
186+
{
187+
var queryValue = request.QueryString.ToString();
188+
return JsonSerializer.Deserialize(queryValue ?? "", returnType);
189+
}
190+
191+
#endregion
192+
193+
#endregion
194+
}
195+

src/Tigernet.Hosting/Tigernet.Hosting.csproj

-4
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,6 @@
77
<Nullable>enable</Nullable>
88
</PropertyGroup>
99

10-
<ItemGroup>
11-
<Folder Include="Extensions\" />
12-
</ItemGroup>
13-
1410
<ItemGroup>
1511
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="7.0.4" />
1612
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />

src/Tigernet.Hosting/TigernetHostBuilder.cs

+34-6
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@
55
using System.Text.Json.Serialization;
66
using Newtonsoft.Json;
77
using Tigernet.Hosting.Attributes.HttpMethods;
8+
using Tigernet.Hosting.Attributes.RequestContents;
89
using Tigernet.Hosting.Attributes.Resters;
910
using Tigernet.Hosting.Exceptions;
11+
using Tigernet.Hosting.Extensions;
1012
using JsonConverter = System.Text.Json.Serialization.JsonConverter;
1113
using JsonSerializer = System.Text.Json.JsonSerializer;
1214

@@ -198,6 +200,13 @@ public void MapResters()
198200
return httpMethodAttributes.FirstOrDefault(a => a != null);
199201
}
200202

203+
/// <summary>
204+
/// Creates a handler function for processing HTTP requests.
205+
/// </summary>
206+
/// <param name="resterType">The type of the RESTful service.</param>
207+
/// <param name="method">The method to invoke on the RESTful service.</param>
208+
/// <param name="attribute">The HTTP method attribute associated with the method.</param>
209+
/// <returns>A delegate representing the handler function.</returns>
201210
private Func<HttpListenerContext, Task> CreateHandlerFunc(Type resterType, MethodInfo method, HttpMethodAttribute attribute)
202211
{
203212
return async context =>
@@ -258,31 +267,50 @@ private Func<HttpListenerContext, Task> CreateHandlerFunc(Type resterType, Metho
258267
};
259268
}
260269

270+
/// <summary>
271+
/// Retrieves the arguments to be passed to the RESTful service method.
272+
/// </summary>
273+
/// <param name="method">The method to invoke on the RESTful service.</param>
274+
/// <param name="context">The HTTP listener context.</param>
275+
/// <returns>An array of objects representing the arguments to be passed to the method.</returns>
261276
private async ValueTask<object[]> GetArguments(MethodInfo method, HttpListenerContext context)
262277
{
263278
var parameters = method.GetParameters();
264279
var args = new object[parameters.Length];
265280

266281
for (int i = 0; i < parameters.Length; i++)
267282
{
268-
var parameterType = parameters[i].ParameterType;
269-
if (parameterType == typeof(HttpListenerContext))
283+
var parameterAttributes =
284+
parameters[i].GetCustomAttributes<RequestContentAttribute>()
285+
?? new List<RequestContentAttribute>();
286+
if (parameterAttributes.Any())
270287
{
271-
args[i] = context;
288+
if (parameterAttributes.Count() > 1)
289+
throw new ArgumentException($"In {method.Name} argument have multiple http request content. In parameter {parameters[i].Name}");
290+
291+
var parameterType = parameters[i].ParameterType;
292+
args[i] = context.Request.GetInjectingRequestData(parameterType,
293+
parameterAttributes!.First()!.DataMapSource);
272294
}
273295
else
274296
{
275297
args[i] = null;
276298
}
277299

278-
var content = await GetRequestContentAsync(context.Request, parameterType);
279-
if (content != default)
280-
args[i] = content;
300+
// var content = await GetRequestContentAsync(context.Request, parameterType);
301+
// if (content != default)
302+
// args[i] = content;
281303
}
282304

283305
return args;
284306
}
285307

308+
/// <summary>
309+
/// Retrieves the content of the HTTP request body and deserializes it to the expected type.
310+
/// </summary>
311+
/// <param name="request">The HTTP listener request.</param>
312+
/// <param name="expectedType">The expected type of the deserialized object.</param>
313+
/// <returns>The deserialized object, or null if the request has no content or deserialization fails.</returns>
286314
private async ValueTask<object?> GetRequestContentAsync(HttpListenerRequest request, Type expectedType)
287315
{
288316
if (request.ContentLength64 == 0)

0 commit comments

Comments
 (0)