Skip to content

Commit 872fd2e

Browse files
authored
Support embedding BaGet into custom ASP.NET Core applications (loic-sharma#538)
This lets you embed BaGet into your own custom ASP.NET Core application. This change removes BaGet's knowledge of the different database and storage providers, thereby allowing BaGet's dependency injection logic to be pushed down to the `BaGet.Hosting` and `BaGet.Core` projects. The app must now register its storage and database providers using the new `BaGetApplication` type.
1 parent ba755d7 commit 872fd2e

File tree

64 files changed

+1669
-932
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

64 files changed

+1669
-932
lines changed

BaGet.sln

+8-1
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BaGet.Gcp", "src\BaGet.Gcp\
4444
EndProject
4545
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{DDEC0736-8169-4834-815E-B78E7CE612A4}"
4646
EndProject
47-
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BaGet.Protocol.Samples.Tests", "samples\BaGet.Protocol.Samples.Tests.csproj", "{16B0D424-BB2F-4C0C-90B0-4F7955326ADF}"
47+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BaGet.Protocol.Samples.Tests", "samples\BaGet.Protocol.Samples.Tests\BaGet.Protocol.Samples.Tests.csproj", "{16B0D424-BB2F-4C0C-90B0-4F7955326ADF}"
4848
EndProject
4949
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BaGet.Aliyun", "src\BaGet.Aliyun\BaGet.Aliyun.csproj", "{9F7C4F38-D598-42D9-A9F8-962490483B18}"
5050
EndProject
51+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BaGetWebApplication", "samples\BaGetWebApplication\BaGetWebApplication.csproj", "{E5AFE55D-0932-46A9-BFA3-C8A034037377}"
52+
EndProject
5153
Global
5254
GlobalSection(SolutionConfigurationPlatforms) = preSolution
5355
Debug|Any CPU = Debug|Any CPU
@@ -118,6 +120,10 @@ Global
118120
{9F7C4F38-D598-42D9-A9F8-962490483B18}.Debug|Any CPU.Build.0 = Debug|Any CPU
119121
{9F7C4F38-D598-42D9-A9F8-962490483B18}.Release|Any CPU.ActiveCfg = Release|Any CPU
120122
{9F7C4F38-D598-42D9-A9F8-962490483B18}.Release|Any CPU.Build.0 = Release|Any CPU
123+
{E5AFE55D-0932-46A9-BFA3-C8A034037377}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
124+
{E5AFE55D-0932-46A9-BFA3-C8A034037377}.Debug|Any CPU.Build.0 = Debug|Any CPU
125+
{E5AFE55D-0932-46A9-BFA3-C8A034037377}.Release|Any CPU.ActiveCfg = Release|Any CPU
126+
{E5AFE55D-0932-46A9-BFA3-C8A034037377}.Release|Any CPU.Build.0 = Release|Any CPU
121127
EndGlobalSection
122128
GlobalSection(SolutionProperties) = preSolution
123129
HideSolutionNode = FALSE
@@ -139,6 +145,7 @@ Global
139145
{D7D60BA0-FF7F-4B37-815C-74D487C5176E} = {26A0B557-53FB-4B9A-94C4-BCCF1BDCB0CC}
140146
{16B0D424-BB2F-4C0C-90B0-4F7955326ADF} = {DDEC0736-8169-4834-815E-B78E7CE612A4}
141147
{9F7C4F38-D598-42D9-A9F8-962490483B18} = {26A0B557-53FB-4B9A-94C4-BCCF1BDCB0CC}
148+
{E5AFE55D-0932-46A9-BFA3-C8A034037377} = {DDEC0736-8169-4834-815E-B78E7CE612A4}
142149
EndGlobalSection
143150
GlobalSection(ExtensibilityGlobals) = postSolution
144151
SolutionGuid = {1423C027-2C90-417F-8629-2A4CF107C055}

samples/BaGet.Protocol.Samples.Tests.csproj samples/BaGet.Protocol.Samples.Tests/BaGet.Protocol.Samples.Tests.csproj

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<Project Sdk="Microsoft.NET.Sdk">
1+
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
44
<TargetFramework>netcoreapp3.0</TargetFramework>
@@ -19,7 +19,7 @@
1919
</ItemGroup>
2020

2121
<ItemGroup>
22-
<ProjectReference Include="..\src\BaGet.Protocol\BaGet.Protocol.csproj" />
22+
<ProjectReference Include="..\..\src\BaGet.Protocol\BaGet.Protocol.csproj" />
2323
</ItemGroup>
2424

2525
</Project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<Project Sdk="Microsoft.NET.Sdk.Web">
2+
3+
<PropertyGroup>
4+
<TargetFramework>netcoreapp3.1</TargetFramework>
5+
</PropertyGroup>
6+
7+
<ItemGroup>
8+
<ProjectReference Include="..\..\src\BaGet.Database.Sqlite\BaGet.Database.Sqlite.csproj" />
9+
<ProjectReference Include="..\..\src\BaGet.Hosting\BaGet.Hosting.csproj" />
10+
</ItemGroup>
11+
12+
</Project>
+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
using System.Threading.Tasks;
2+
using BaGet.Hosting;
3+
using Microsoft.AspNetCore.Hosting;
4+
using Microsoft.Extensions.Hosting;
5+
6+
namespace BaGetWebApplication
7+
{
8+
public class Program
9+
{
10+
public static async Task Main(string[] args)
11+
{
12+
var host = CreateHostBuilder(args).Build();
13+
14+
await host.RunMigrationsAsync();
15+
host.Run();
16+
}
17+
18+
public static IHostBuilder CreateHostBuilder(string[] args) =>
19+
Host.CreateDefaultBuilder(args)
20+
.ConfigureWebHostDefaults(webBuilder =>
21+
{
22+
webBuilder.UseStartup<Startup>();
23+
});
24+
}
25+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{
2+
"iisSettings": {
3+
"windowsAuthentication": false,
4+
"anonymousAuthentication": true,
5+
"iisExpress": {
6+
"applicationUrl": "http://localhost:60558",
7+
"sslPort": 44309
8+
}
9+
},
10+
"profiles": {
11+
"IIS Express": {
12+
"commandName": "IISExpress",
13+
"launchBrowser": true,
14+
"environmentVariables": {
15+
"ASPNETCORE_ENVIRONMENT": "Development"
16+
}
17+
},
18+
"BaGetWebApplication": {
19+
"commandName": "Project",
20+
"launchBrowser": true,
21+
"applicationUrl": "https://localhost:5001;http://localhost:5000",
22+
"environmentVariables": {
23+
"ASPNETCORE_ENVIRONMENT": "Development"
24+
}
25+
}
26+
}
27+
}
+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
using BaGet;
2+
using BaGet.Core;
3+
using Microsoft.AspNetCore.Builder;
4+
using Microsoft.AspNetCore.Hosting;
5+
using Microsoft.AspNetCore.Http;
6+
using Microsoft.Extensions.DependencyInjection;
7+
using Microsoft.Extensions.Hosting;
8+
9+
namespace BaGetWebApplication
10+
{
11+
public class Startup
12+
{
13+
public void ConfigureServices(IServiceCollection services)
14+
{
15+
services.AddBaGetWebApplication(app =>
16+
{
17+
// Use SQLite as BaGet's database and store packages on the local file system.
18+
app.AddSqliteDatabase();
19+
app.AddFileStorage();
20+
});
21+
}
22+
23+
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
24+
{
25+
if (env.IsDevelopment())
26+
{
27+
app.UseDeveloperExceptionPage();
28+
}
29+
30+
app.UseRouting();
31+
32+
app.UseEndpoints(endpoints =>
33+
{
34+
// Add BaGet's endpoints.
35+
var api = new BaGetApi();
36+
37+
api.MapRoutes(endpoints);
38+
39+
// Add a "welcome" endpoint to help you find the package source.
40+
// This is optional, you can remove this endpoint if you'd like.
41+
endpoints.MapGet("/", async context =>
42+
{
43+
var url = context.RequestServices.GetRequiredService<IUrlGenerator>();
44+
var packageSource = url.GetServiceIndexUrl();
45+
46+
await context.Response.WriteAsync($"Package source URL: '{packageSource}'");
47+
});
48+
});
49+
}
50+
}
51+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"Logging": {
3+
"LogLevel": {
4+
"Default": "Information",
5+
"Microsoft": "Warning",
6+
"Microsoft.Hosting.Lifetime": "Information"
7+
}
8+
}
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"Database": {
3+
"ConnectionString": "Data Source=baget.db"
4+
},
5+
6+
"Logging": {
7+
"LogLevel": {
8+
"Default": "Information",
9+
"Microsoft": "Warning",
10+
"Microsoft.Hosting.Lifetime": "Information"
11+
}
12+
},
13+
"AllowedHosts": "*"
14+
}

samples/readme.md

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Samples
2+
3+
Here you can find samples that show you how to use BaGet in your own projects:
4+
5+
* `BaGetWebApplication` - Embed BaGet into your own ASP.NET Core project
6+
* `BaGet.Protocol.Samples.Tests` - Interact with a NuGet V3 API
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
using System;
2+
using Aliyun.OSS;
3+
using BaGet.Aliyun;
4+
using BaGet.Core;
5+
using Microsoft.Extensions.DependencyInjection;
6+
using Microsoft.Extensions.DependencyInjection.Extensions;
7+
using Microsoft.Extensions.Options;
8+
9+
namespace BaGet
10+
{
11+
public static class AliyunApplicationExtensions
12+
{
13+
public static BaGetApplication AddAliyunOssStorage(this BaGetApplication app)
14+
{
15+
app.Services.AddBaGetOptions<AliyunStorageOptions>(nameof(BaGetOptions.Storage));
16+
17+
app.Services.AddTransient<AliyunStorageService>();
18+
app.Services.TryAddTransient<IStorageService>(provider => provider.GetRequiredService<AliyunStorageService>());
19+
20+
app.Services.AddSingleton(provider =>
21+
{
22+
var options = provider.GetRequiredService<IOptions<AliyunStorageOptions>>().Value;
23+
24+
return new OssClient(options.Endpoint, options.AccessKey, options.AccessKeySecret);
25+
});
26+
27+
app.Services.AddProvider<IStorageService>((provider, config) =>
28+
{
29+
if (!config.HasStorageType("AliyunOss")) return null;
30+
31+
return provider.GetRequiredService<AliyunStorageService>();
32+
});
33+
34+
return app;
35+
}
36+
37+
public static BaGetApplication AddAliyunOssStorage(
38+
this BaGetApplication app,
39+
Action<AliyunStorageOptions> configure)
40+
{
41+
app.AddAliyunOssStorage();
42+
app.Services.Configure(configure);
43+
return app;
44+
}
45+
}
46+
}

src/BaGet.Aliyun/Extensions/ServiceCollectionExtensions.cs

-23
This file was deleted.
+96
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
using System;
2+
using System.Threading.Tasks;
3+
using Amazon;
4+
using Amazon.Runtime;
5+
using Amazon.S3;
6+
using BaGet.Aws;
7+
using BaGet.Core;
8+
using Microsoft.Extensions.DependencyInjection;
9+
using Microsoft.Extensions.DependencyInjection.Extensions;
10+
using Microsoft.Extensions.Options;
11+
12+
namespace BaGet
13+
{
14+
public static class AwsApplicationExtensions
15+
{
16+
public static BaGetApplication AddAwsS3Storage(this BaGetApplication app)
17+
{
18+
app.Services.AddBaGetOptions<S3StorageOptions>(nameof(BaGetOptions.Storage));
19+
20+
app.Services.AddTransient<S3StorageService>();
21+
app.Services.TryAddTransient<IStorageService>(provider => provider.GetRequiredService<S3StorageService>());
22+
23+
app.Services.AddProvider<IStorageService>((provider, config) =>
24+
{
25+
if (!config.HasStorageType("AwsS3")) return null;
26+
27+
return provider.GetRequiredService<S3StorageService>();
28+
});
29+
30+
app.Services.AddSingleton(provider =>
31+
{
32+
var options = provider.GetRequiredService<IOptions<S3StorageOptions>>().Value;
33+
34+
var config = new AmazonS3Config
35+
{
36+
RegionEndpoint = RegionEndpoint.GetBySystemName(options.Region)
37+
};
38+
39+
if (options.UseInstanceProfile)
40+
{
41+
var credentials = FallbackCredentialsFactory.GetCredentials();
42+
return new AmazonS3Client(credentials, config);
43+
}
44+
45+
if (!string.IsNullOrEmpty(options.AssumeRoleArn))
46+
{
47+
var credentials = FallbackCredentialsFactory.GetCredentials();
48+
var assumedCredentials = AssumeRoleAsync(
49+
credentials,
50+
options.AssumeRoleArn,
51+
$"BaGet-Session-{Guid.NewGuid()}")
52+
.GetAwaiter()
53+
.GetResult();
54+
55+
return new AmazonS3Client(assumedCredentials, config);
56+
}
57+
58+
if (!string.IsNullOrEmpty(options.AccessKey))
59+
{
60+
return new AmazonS3Client(
61+
new BasicAWSCredentials(
62+
options.AccessKey,
63+
options.SecretKey),
64+
config);
65+
}
66+
67+
return new AmazonS3Client(config);
68+
});
69+
70+
return app;
71+
}
72+
73+
public static BaGetApplication AddAwsS3Storage(this BaGetApplication app, Action<S3StorageOptions> configure)
74+
{
75+
app.AddAwsS3Storage();
76+
app.Services.Configure(configure);
77+
return app;
78+
}
79+
80+
private static async Task<AWSCredentials> AssumeRoleAsync(
81+
AWSCredentials credentials,
82+
string roleArn,
83+
string roleSessionName)
84+
{
85+
var assumedCredentials = new AssumeRoleAWSCredentials(credentials, roleArn, roleSessionName);
86+
var immutableCredentials = await credentials.GetCredentialsAsync();
87+
88+
if (string.IsNullOrWhiteSpace(immutableCredentials.Token))
89+
{
90+
throw new InvalidOperationException($"Unable to assume role {roleArn}");
91+
}
92+
93+
return assumedCredentials;
94+
}
95+
}
96+
}

0 commit comments

Comments
 (0)