Skip to content
Draft
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,16 @@
<PackageVersion Include="System.Globalization" Version="4.3.0" />
<PackageVersion Include="System.Runtime.Extensions" Version="4.3.1" />
<PackageVersion Include="Serilog.AspNetCore" Version="9.0.0" />
<PackageVersion Include="Azure.Storage.Blobs" Version="12.19.1" />
<PackageVersion Include="Azure.Identity" Version="1.12.0" />
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.8" />
<PackageVersion Include="Microsoft.Extensions.Configuration" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.Configuration.Json" Version="8.0.0" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net8.0'">
<PackageVersion Include="Microsoft.AspNetCore.Authorization" Version="9.0.8" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="8.0.2" />
<PackageVersion Include="Microsoft.Extensions.Configuration" Version="8.0.0" />
<PackageVersion Include="Microsoft.AspNetCore.OpenApi" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.Configuration.Abstractions" Version="9.0.8" />
<PackageVersion Include="Microsoft.Extensions.Configuration.Binder" Version="9.0.8" />
<PackageVersion Include="Microsoft.Extensions.Configuration.CommandLine" Version="8.0.0" />
Expand All @@ -42,7 +47,6 @@
<PackageVersion Include="Microsoft.AspNetCore.Authorization" Version="9.0.8" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="9.0.5" />
<PackageVersion Include="Microsoft.AspNetCore.OpenApi" Version="9.0.5" />
<PackageVersion Include="Microsoft.Extensions.Configuration" Version="9.0.5" />
<PackageVersion Include="Microsoft.Extensions.Configuration.Abstractions" Version="9.0.8" />
<PackageVersion Include="Microsoft.Extensions.Configuration.Binder" Version="9.0.8" />
<PackageVersion Include="Microsoft.Extensions.Configuration.CommandLine" Version="9.0.5" />
Expand Down Expand Up @@ -70,7 +74,6 @@
<PackageVersion Include="Microsoft.AspNetCore.Authorization" Version="9.0.0" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="9.0.5" />
<PackageVersion Include="Microsoft.AspNetCore.OpenApi" Version="9.0.5" />
<PackageVersion Include="Microsoft.Extensions.Configuration" Version="9.0.5" />
<PackageVersion Include="Microsoft.Extensions.Configuration.Abstractions" Version="9.0.8" />
<PackageVersion Include="Microsoft.Extensions.Configuration.Binder" Version="9.0.8" />
<PackageVersion Include="Microsoft.Extensions.Configuration.CommandLine" Version="9.0.5" />
Expand Down
54 changes: 54 additions & 0 deletions WOPI.sln
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WopiHost.AppHost", "infra\W
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WopiHost.ServiceDefaults", "infra\WopiHost.ServiceDefaults\WopiHost.ServiceDefaults.csproj", "{8EF68B93-D00E-440D-9267-277FC39961A5}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WopiHost.AzureStorageProvider", "src\WopiHost.AzureStorageProvider\WopiHost.AzureStorageProvider.csproj", "{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WopiHost.AzureStorageProvider.Tests", "test\WopiHost.AzureStorageProvider.Tests\WopiHost.AzureStorageProvider.Tests.csproj", "{F5EF51B5-F8D8-4DF4-89EC-55ECBDA7AC12}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WopiHost.AzureStorageProvider.Sample", "sample\WopiHost.AzureStorageProvider\WopiHost.AzureStorageProvider.Sample.csproj", "{67496D2A-8F52-4C50-AD41-AFC90767172C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -371,6 +377,54 @@ Global
{8EF68B93-D00E-440D-9267-277FC39961A5}.Release|x64.Build.0 = Release|Any CPU
{8EF68B93-D00E-440D-9267-277FC39961A5}.Release|x86.ActiveCfg = Release|Any CPU
{8EF68B93-D00E-440D-9267-277FC39961A5}.Release|x86.Build.0 = Release|Any CPU
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|x64.ActiveCfg = Debug|Any CPU
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|x64.Build.0 = Debug|Any CPU
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|x86.ActiveCfg = Debug|Any CPU
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|x86.Build.0 = Debug|Any CPU
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|Any CPU.Build.0 = Release|Any CPU
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|x64.ActiveCfg = Release|Any CPU
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|x64.Build.0 = Release|Any CPU
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|x86.ActiveCfg = Release|Any CPU
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|x86.Build.0 = Release|Any CPU
{F5EF51B5-F8D8-4DF4-89EC-55ECBDA7AC12}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F5EF51B5-F8D8-4DF4-89EC-55ECBDA7AC12}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F5EF51B5-F8D8-4DF4-89EC-55ECBDA7AC12}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{F5EF51B5-F8D8-4DF4-89EC-55ECBDA7AC12}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{F5EF51B5-F8D8-4DF4-89EC-55ECBDA7AC12}.Debug|x64.ActiveCfg = Debug|Any CPU
{F5EF51B5-F8D8-4DF4-89EC-55ECBDA7AC12}.Debug|x64.Build.0 = Debug|Any CPU
{F5EF51B5-F8D8-4DF4-89EC-55ECBDA7AC12}.Debug|x86.ActiveCfg = Debug|Any CPU
{F5EF51B5-F8D8-4DF4-89EC-55ECBDA7AC12}.Debug|x86.Build.0 = Debug|Any CPU
{F5EF51B5-F8D8-4DF4-89EC-55ECBDA7AC12}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F5EF51B5-F8D8-4DF4-89EC-55ECBDA7AC12}.Release|Any CPU.Build.0 = Release|Any CPU
{F5EF51B5-F8D8-4DF4-89EC-55ECBDA7AC12}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{F5EF51B5-F8D8-4DF4-89EC-55ECBDA7AC12}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{F5EF51B5-F8D8-4DF4-89EC-55ECBDA7AC12}.Release|x64.ActiveCfg = Release|Any CPU
{F5EF51B5-F8D8-4DF4-89EC-55ECBDA7AC12}.Release|x64.Build.0 = Release|Any CPU
{F5EF51B5-F8D8-4DF4-89EC-55ECBDA7AC12}.Release|x86.ActiveCfg = Release|Any CPU
{F5EF51B5-F8D8-4DF4-89EC-55ECBDA7AC12}.Release|x86.Build.0 = Release|Any CPU
{67496D2A-8F52-4C50-AD41-AFC90767172C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{67496D2A-8F52-4C50-AD41-AFC90767172C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{67496D2A-8F52-4C50-AD41-AFC90767172C}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{67496D2A-8F52-4C50-AD41-AFC90767172C}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{67496D2A-8F52-4C50-AD41-AFC90767172C}.Debug|x64.ActiveCfg = Debug|Any CPU
{67496D2A-8F52-4C50-AD41-AFC90767172C}.Debug|x64.Build.0 = Debug|Any CPU
{67496D2A-8F52-4C50-AD41-AFC90767172C}.Debug|x86.ActiveCfg = Debug|Any CPU
{67496D2A-8F52-4C50-AD41-AFC90767172C}.Debug|x86.Build.0 = Debug|Any CPU
{67496D2A-8F52-4C50-AD41-AFC90767172C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{67496D2A-8F52-4C50-AD41-AFC90767172C}.Release|Any CPU.Build.0 = Release|Any CPU
{67496D2A-8F52-4C50-AD41-AFC90767172C}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{67496D2A-8F52-4C50-AD41-AFC90767172C}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{67496D2A-8F52-4C50-AD41-AFC90767172C}.Release|x64.ActiveCfg = Release|Any CPU
{67496D2A-8F52-4C50-AD41-AFC90767172C}.Release|x64.Build.0 = Release|Any CPU
{67496D2A-8F52-4C50-AD41-AFC90767172C}.Release|x86.ActiveCfg = Release|Any CPU
{67496D2A-8F52-4C50-AD41-AFC90767172C}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
40 changes: 40 additions & 0 deletions sample/WopiHost.AzureStorageProvider/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using WopiHost.AzureStorageProvider;
using WopiHost.Core.Extensions;
using WopiHost.Abstractions;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddControllers();

// Configure Azure Storage provider
builder.Services.Configure<WopiAzureStorageProviderOptions>(
builder.Configuration.GetSection("WopiHost:StorageOptions"));

// Register Azure Storage services
builder.Services.AddSingleton<AzureFileIds>();
builder.Services.AddScoped<IWopiStorageProvider, WopiAzureStorageProvider>();
builder.Services.AddScoped<IWopiWritableStorageProvider, WopiAzureStorageProvider>();
builder.Services.AddScoped<IWopiSecurityHandler, WopiAzureSecurityHandler>();

// Add WOPI services
builder.Services.AddWopi();

// Add OpenAPI services
builder.Services.AddEndpointsApiExplorer();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
// OpenAPI endpoint will be available at /openapi/v1.json
}

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"profiles": {
"WopiHost.AzureStorageProvider.Sample": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "https://localhost:3702;http://localhost:3703"
}
}
}
106 changes: 106 additions & 0 deletions sample/WopiHost.AzureStorageProvider/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
# WopiHost.AzureStorageProvider Sample

This sample demonstrates how to use the WopiHost.AzureStorageProvider with Azure Blob Storage.

## Prerequisites

1. An Azure Storage Account
2. .NET 8.0 or later
3. Visual Studio 2022 or VS Code

## Configuration

1. Update the `appsettings.json` file with your Azure Storage connection details:

```json
{
"WopiHost": {
"StorageOptions": {
"ConnectionString": "DefaultEndpointsProtocol=https;AccountName=yourstorageaccount;AccountKey=yourkey;EndpointSuffix=core.windows.net",
"ContainerName": "wopi-files",
"RootPath": "documents",
"UseManagedIdentity": false,
"CreateContainerIfNotExists": true
},
"ClientUrl": "https://your-office-online-server.com/hosting/discovery"
}
}
```

## Running the Sample

1. Navigate to the sample directory:
```bash
cd sample/WopiHost.AzureStorageProvider
```

2. Restore packages:
```bash
dotnet restore
```

3. Run the application:
```bash
dotnet run
```

4. Open your browser and navigate to `https://localhost:5001` (or the URL shown in the console)
5. The OpenAPI specification will be available at `/openapi/v1.json`

## Features Demonstrated

- Azure Blob Storage integration
- File upload/download operations
- Container management
- Security handling
- WOPI protocol implementation

## Authentication Options

The sample supports multiple authentication methods:

### Connection String
```json
{
"StorageOptions": {
"ConnectionString": "DefaultEndpointsProtocol=https;AccountName=...",
"ContainerName": "wopi-files"
}
}
```

### Account Key
```json
{
"StorageOptions": {
"AccountName": "yourstorageaccount",
"AccountKey": "yourkey",
"ContainerName": "wopi-files"
}
}
```

### Managed Identity
```json
{
"StorageOptions": {
"AccountName": "yourstorageaccount",
"UseManagedIdentity": true,
"ContainerName": "wopi-files"
}
}
```

## Testing

You can test the WOPI endpoints using tools like Postman or curl:

- Discovery: `GET /wopi/discovery`
- CheckFileInfo: `GET /wopi/files/{fileId}`
- GetFile: `GET /wopi/files/{fileId}/contents`

## Troubleshooting

1. **Container not found**: Ensure the container exists or set `CreateContainerIfNotExists` to `true`
2. **Authentication failed**: Verify your connection string or account credentials
3. **Permission denied**: Check that your Azure Storage account has the necessary permissions
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFrameworks>net8.0;net9.0;net10.0</TargetFrameworks>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<AssemblyName>WopiHost.AzureStorageProvider.Sample</AssemblyName>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\WopiHost.AzureStorageProvider\WopiHost.AzureStorageProvider.csproj" />
<ProjectReference Include="..\..\src\WopiHost.Core\WopiHost.Core.csproj" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.OpenApi" />
</ItemGroup>

</Project>
20 changes: 20 additions & 0 deletions sample/WopiHost.AzureStorageProvider/appsettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"WopiHost": {
"StorageOptions": {
"ConnectionString": "DefaultEndpointsProtocol=https;AccountName=yourstorageaccount;AccountKey=yourkey;EndpointSuffix=core.windows.net",
"ContainerName": "wopi-files",
"RootPath": "documents",
"UseManagedIdentity": false,
"CreateContainerIfNotExists": true,
"FileNameMaxLength": 250
},
"ClientUrl": "https://your-office-online-server.com/hosting/discovery"
}
}
Loading