-
Notifications
You must be signed in to change notification settings - Fork 4.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added CM ASP.NET extensions and CM metapackage (#47021)
* added ASp.NET extensions package * added ASP.NET extensions package * updated apis
- Loading branch information
1 parent
99f387a
commit f9995e7
Showing
10 changed files
with
391 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
# Release History | ||
|
||
## 1.0.0-beta.1 (Unreleased) | ||
|
||
### Features Added | ||
|
||
### Breaking Changes | ||
|
||
### Bugs Fixed | ||
|
||
### Other Changes |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
# ASP.NET COre extensions for Azure CloudMachine client library for .NET | ||
|
||
TODO | ||
|
||
## Getting started | ||
|
||
### Install the package | ||
|
||
Install the client library for .NET with [NuGet](https://www.nuget.org/ ): | ||
|
||
```dotnetcli | ||
dotnet add package Azure.CloudMachine --prerelease | ||
``` | ||
|
||
### Prerequisites | ||
|
||
> You must have an [Azure subscription](https://azure.microsoft.com/free/dotnet/). | ||
### Authenticate the Client | ||
|
||
## Key concepts | ||
|
||
TODO. | ||
|
||
## Examples | ||
|
||
## Troubleshooting | ||
|
||
- File an issue via [GitHub Issues](https://github.com/Azure/azure-sdk-for-net/issues). | ||
- Check [previous questions](https://stackoverflow.com/questions/tagged/azure+.net) or ask new ones on Stack Overflow using Azure and .NET tags. | ||
|
||
## Next steps | ||
|
||
## Contributing | ||
|
||
For details on contributing to this repository, see the [contributing | ||
guide][cg]. | ||
|
||
This project welcomes contributions and suggestions. Most contributions | ||
require you to agree to a Contributor License Agreement (CLA) declaring | ||
that you have the right to, and actually do, grant us the rights to use | ||
your contribution. For details, visit <https://cla.microsoft.com>. | ||
|
||
When you submit a pull request, a CLA-bot will automatically determine | ||
whether you need to provide a CLA and decorate the PR appropriately | ||
(for example, label, comment). Follow the instructions provided by the | ||
bot. You'll only need to do this action once across all repositories | ||
using our CLA. | ||
|
||
This project has adopted the [Microsoft Open Source Code of Conduct][coc]. For | ||
more information, see the [Code of Conduct FAQ][coc_faq] or contact | ||
<opencode@microsoft.com> with any other questions or comments. | ||
|
||
<!-- LINKS --> | ||
[cg]: https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/resourcemanager/Azure.ResourceManager/docs/CONTRIBUTING.md | ||
[coc]: https://opensource.microsoft.com/codeofconduct/ | ||
[coc_faq]: https://opensource.microsoft.com/codeofconduct/faq/ |
Empty file.
18 changes: 18 additions & 0 deletions
18
sdk/cloudmachine/Azure.CloudMachine.All/src/Azure.CloudMachine.All.csproj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<Description>Azure.CloudMachine Metapackage</Description> | ||
<Version>1.0.0-beta.1</Version> | ||
<TargetFrameworks>net8.0</TargetFrameworks> | ||
<RequiredTargetFrameworks>net8.0</RequiredTargetFrameworks> | ||
<Nullable>enable</Nullable> | ||
<LangVersion>12</LangVersion> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<ProjectReference Include="..\..\..\provisioning\Azure.Provisioning.CloudMachine\src\Azure.Provisioning.CloudMachine.csproj" /> | ||
<ProjectReference Include="..\..\Azure.CloudMachine.Web\src\Azure.CloudMachine.Web.csproj" /> | ||
<ProjectReference Include="..\..\Azure.CloudMachine\src\Azure.CloudMachine.csproj" /> | ||
</ItemGroup> | ||
|
||
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
# Release History | ||
|
||
## 1.0.0-beta.1 (Unreleased) | ||
|
||
### Features Added | ||
|
||
### Breaking Changes | ||
|
||
### Bugs Fixed | ||
|
||
### Other Changes |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
# ASP.NET COre extensions for Azure CloudMachine client library for .NET | ||
|
||
TODO | ||
|
||
## Getting started | ||
|
||
### Install the package | ||
|
||
Install the client library for .NET with [NuGet](https://www.nuget.org/ ): | ||
|
||
```dotnetcli | ||
dotnet add package Azure.CloudMachine --prerelease | ||
``` | ||
|
||
### Prerequisites | ||
|
||
> You must have an [Azure subscription](https://azure.microsoft.com/free/dotnet/). | ||
### Authenticate the Client | ||
|
||
## Key concepts | ||
|
||
TODO. | ||
|
||
## Examples | ||
|
||
## Troubleshooting | ||
|
||
- File an issue via [GitHub Issues](https://github.com/Azure/azure-sdk-for-net/issues). | ||
- Check [previous questions](https://stackoverflow.com/questions/tagged/azure+.net) or ask new ones on Stack Overflow using Azure and .NET tags. | ||
|
||
## Next steps | ||
|
||
## Contributing | ||
|
||
For details on contributing to this repository, see the [contributing | ||
guide][cg]. | ||
|
||
This project welcomes contributions and suggestions. Most contributions | ||
require you to agree to a Contributor License Agreement (CLA) declaring | ||
that you have the right to, and actually do, grant us the rights to use | ||
your contribution. For details, visit <https://cla.microsoft.com>. | ||
|
||
When you submit a pull request, a CLA-bot will automatically determine | ||
whether you need to provide a CLA and decorate the PR appropriately | ||
(for example, label, comment). Follow the instructions provided by the | ||
bot. You'll only need to do this action once across all repositories | ||
using our CLA. | ||
|
||
This project has adopted the [Microsoft Open Source Code of Conduct][coc]. For | ||
more information, see the [Code of Conduct FAQ][coc_faq] or contact | ||
<opencode@microsoft.com> with any other questions or comments. | ||
|
||
<!-- LINKS --> | ||
[cg]: https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/resourcemanager/Azure.ResourceManager/docs/CONTRIBUTING.md | ||
[coc]: https://opensource.microsoft.com/codeofconduct/ | ||
[coc_faq]: https://opensource.microsoft.com/codeofconduct/faq/ |
8 changes: 8 additions & 0 deletions
8
sdk/cloudmachine/Azure.CloudMachine.Web/api/Azure.CloudMachine.Web.net8.0.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
namespace System.ClientModel.TypeSpec | ||
{ | ||
public static partial class CloudMachineExtensions | ||
{ | ||
public static void Map<T>(this Microsoft.AspNetCore.Routing.IEndpointRouteBuilder routeBuilder, T serviceImplementation) where T : class { } | ||
public static System.Threading.Tasks.Task UploadFormAsync(this Azure.CloudMachine.StorageServices storage, Microsoft.AspNetCore.Http.HttpRequest multiPartFormData) { throw null; } | ||
} | ||
} |
26 changes: 26 additions & 0 deletions
26
sdk/cloudmachine/Azure.CloudMachine.Web/src/Azure.CloudMachine.Web.csproj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<Description>Azure.CloudMachine.Web is an ASP.NET Core extensions for Azure.CloudMachine</Description> | ||
<Version>1.0.0-beta.1</Version> | ||
<TargetFrameworks>net8.0</TargetFrameworks> | ||
<RequiredTargetFrameworks>net8.0</RequiredTargetFrameworks> | ||
<Nullable>enable</Nullable> | ||
<LangVersion>12</LangVersion> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<Compile Remove="Properties\**" /> | ||
<EmbeddedResource Remove="Properties\**" /> | ||
<None Remove="Properties\**" /> | ||
</ItemGroup> | ||
|
||
<ItemGroup> | ||
<PackageReference Include="System.Memory.Data" VersionOverride="8.0.0" /> | ||
<FrameworkReference Include="Microsoft.AspNetCore.App" /> | ||
</ItemGroup> | ||
|
||
<ItemGroup> | ||
<ProjectReference Include="..\..\Azure.CloudMachine\src\Azure.CloudMachine.csproj" /> | ||
</ItemGroup> | ||
</Project> |
191 changes: 191 additions & 0 deletions
191
sdk/cloudmachine/Azure.CloudMachine.Web/src/CloudMachineExtensions.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,191 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. | ||
|
||
using System.Reflection; | ||
using Microsoft.AspNetCore.Mvc; | ||
using System.Diagnostics; | ||
using System.IO; | ||
using System.Threading.Tasks; | ||
using Azure.CloudMachine; | ||
using Microsoft.AspNetCore.Http; | ||
using Microsoft.AspNetCore.Routing; | ||
using Microsoft.AspNetCore.Builder; | ||
|
||
namespace System.ClientModel.TypeSpec; | ||
|
||
/// <summary> | ||
/// ASp.NET Core extension methods for mapping a service implementation to a set of HTTP endpoints. | ||
/// </summary> | ||
public static class CloudMachineExtensions | ||
{ | ||
/// <summary> | ||
/// Uploads a document to the storage service. | ||
/// </summary> | ||
/// <param name="storage"></param> | ||
/// <param name="multiPartFormData"></param> | ||
/// <returns></returns> | ||
public static async Task UploadFormAsync(this StorageServices storage, HttpRequest multiPartFormData) | ||
{ | ||
IFormCollection form = await multiPartFormData.ReadFormAsync().ConfigureAwait(false); | ||
IFormFile? file = form.Files.GetFile("file"); | ||
Stream? fileStram = file!.OpenReadStream(); | ||
await storage.UploadAsync(fileStram, file.FileName, file.ContentType, overwrite: true).ConfigureAwait(false); | ||
} | ||
|
||
/// <summary> | ||
/// Maps a service implementation to a set of HTTP endpoints. | ||
/// </summary> | ||
/// <typeparam name="T"></typeparam> | ||
/// <param name="routeBuilder"></param> | ||
/// <param name="serviceImplementation"></param> | ||
public static void Map<T>(this IEndpointRouteBuilder routeBuilder, T serviceImplementation) where T : class | ||
{ | ||
Type serviceImplementationType = typeof(T); | ||
Type serviceDescriptor = GetServiceDescriptor(serviceImplementationType); | ||
MethodInfo[] serviceOperations = serviceDescriptor.GetMethods(); | ||
foreach (MethodInfo serviceOperation in serviceOperations) | ||
{ | ||
RequestDelegate handler = CreateRequestDelegate(serviceImplementation, serviceOperation); | ||
string name = serviceOperation.Name; | ||
if (name.EndsWith("Async")) | ||
name = name.Substring(0, name.Length - "Async".Length); | ||
routeBuilder.Map($"/{name}", handler); | ||
} | ||
} | ||
|
||
private static Type GetServiceDescriptor(Type serviceImplementation) | ||
{ | ||
Type[] interfaces = serviceImplementation.GetInterfaces(); | ||
if (interfaces.Length != 1) | ||
throw new InvalidOperationException($"Service {serviceImplementation} must implement exactly one interface"); | ||
Type interfaceType = interfaces[0]; | ||
return interfaceType; | ||
} | ||
|
||
private static RequestDelegate CreateRequestDelegate<T>(T service, MethodInfo implementationMethod) where T : class | ||
{ | ||
return async (HttpContext context) => { | ||
HttpRequest request = context.Request; | ||
|
||
Type serviceType = service.GetType(); | ||
Type interfaceType = GetServiceDescriptor(serviceType); | ||
MethodInfo? interfaceMethod = interfaceType.GetMethod(implementationMethod.Name, BindingFlags.Public | BindingFlags.Instance); | ||
|
||
ParameterInfo[] parameters = interfaceMethod!.GetParameters(); | ||
object[] implementationArguments = new object[parameters.Length]; | ||
|
||
foreach (var parameter in parameters) | ||
{ | ||
implementationArguments[0] = await CreateArgumentAsync(parameter, request).ConfigureAwait(false); | ||
} | ||
|
||
// deal with async APIs | ||
object? implementationReturnValue = implementationMethod.Invoke(service, implementationArguments); | ||
if (implementationReturnValue != default) | ||
{ | ||
Task? task = implementationReturnValue as Task; | ||
if (task != default) | ||
{ | ||
await task.ConfigureAwait(false); | ||
implementationReturnValue = task.GetType().GetProperty("Result")!.GetValue(task); | ||
} | ||
else | ||
{ // TODO: we need to deal with ValueTask too | ||
implementationReturnValue = default; | ||
} | ||
} | ||
else | ||
{ | ||
Debug.Assert(implementationArguments.Length == 0); | ||
} | ||
|
||
HttpResponse response = context.Response; | ||
response.StatusCode = 200; | ||
if (implementationReturnValue != default) | ||
{ | ||
BinaryData responseBody = Serialize(implementationReturnValue); | ||
response.ContentLength = responseBody.ToMemory().Length; | ||
response.ContentType = "application/json"; | ||
await response.Body.WriteAsync(responseBody.ToArray()).ConfigureAwait(false); | ||
} | ||
}; | ||
} | ||
|
||
private static async ValueTask<object> CreateArgumentAsync(ParameterInfo parameter, HttpRequest request) | ||
{ | ||
Type parameterType = parameter.ParameterType; | ||
|
||
if (parameterType == typeof(HttpRequest)) | ||
{ | ||
return request; | ||
} | ||
|
||
if (parameterType == typeof(Stream)) | ||
{ | ||
return request.Body; | ||
} | ||
|
||
if (parameterType == typeof(byte[])) | ||
{ | ||
var bd = await BinaryData.FromStreamAsync(request.Body).ConfigureAwait(false); | ||
return bd.ToArray(); | ||
} | ||
if (parameterType == typeof(BinaryData)) | ||
{ | ||
string? contentType = request.ContentType; | ||
var bd = await BinaryData.FromStreamAsync(request.Body, contentType).ConfigureAwait(false); | ||
return bd; | ||
} | ||
if (parameterType == typeof(string)) | ||
{ | ||
return await new StreamReader(request.Body).ReadToEndAsync().ConfigureAwait(false); | ||
} | ||
|
||
FromQueryAttribute? fqa = parameter.GetCustomAttribute<FromQueryAttribute>(); | ||
if (fqa != default) | ||
{ | ||
string? queryValue = request.Query[parameter.Name!]; | ||
return Convert.ChangeType(queryValue!, parameterType); | ||
} | ||
|
||
FromHeaderAttribute? fha = parameter.GetCustomAttribute<FromHeaderAttribute>(); | ||
if (fha != default) | ||
{ | ||
var headerName = fha.Name ?? parameter.Name; | ||
string? headerValue = request.Headers[headerName!]; | ||
return Convert.ChangeType(headerValue!, parameterType); | ||
} | ||
|
||
object deserialized = DeserializeModel(parameterType, request.Body); | ||
return deserialized; | ||
} | ||
|
||
// TODO: this is a hack. We should use MRW | ||
private static object DeserializeModel(Type modelType, Stream stream) | ||
{ | ||
var fromJson = modelType.GetMethod("FromJson", BindingFlags.Static); | ||
if (fromJson == default) | ||
throw new InvalidOperationException($"{modelType} does not provide FromJson static method"); | ||
object? deserialized = fromJson.Invoke(null, new object[] { stream }); | ||
if (deserialized == default) | ||
throw new InvalidOperationException($"Failed to deserialize {modelType}"); | ||
return deserialized; | ||
} | ||
|
||
private static BinaryData Serialize(object implementationReturnValue) | ||
{ | ||
Type type = implementationReturnValue.GetType(); | ||
if (type.IsGenericType) | ||
{ | ||
if (type.GetGenericTypeDefinition() == typeof(ValueTask<>)) | ||
{ | ||
} | ||
if (type.GetGenericTypeDefinition() == typeof(Task<>)) | ||
{ | ||
} | ||
} | ||
|
||
BinaryData bd = BinaryData.FromObjectAsJson(implementationReturnValue); | ||
return bd; | ||
} | ||
} |
Oops, something went wrong.