Skip to content

Implement IFileProviderFactory, move shared infrastructure to Umbraco.StorageProviders and support Umbraco 10 #36

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 27 commits into from
May 11, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
b3990e5
Add IFileProvider implementation
ronaldbarendse Mar 21, 2022
21211b0
Implement IFileProviderFactory and remove custom middleware
ronaldbarendse Mar 21, 2022
d34039a
Remove AzureBlobFileSystemImageProvider
ronaldbarendse Mar 21, 2022
bcead5e
Fix IAzureBlobFileSystem instance creation
ronaldbarendse Mar 21, 2022
8a42b64
Code/documentation cleanup
ronaldbarendse Mar 21, 2022
d6778b8
Move provider-independent code to Umbraco.StorageProviders project
ronaldbarendse Aug 26, 2021
7b96a0f
Update CDN config section path and documentation
ronaldbarendse Mar 22, 2022
2303f8b
Simplify build and versioning
ronaldbarendse Mar 22, 2022
8786c90
Simplify build and versioning for v2
ronaldbarendse Mar 23, 2022
7ca48b5
Fix caching of NuGet packages caching (use explicit path, add restore…
ronaldbarendse Mar 23, 2022
a1018db
Add additional constructor to allow configuration using managed ident…
ronaldbarendse Mar 23, 2022
9c141d0
Also add additional constructor on image cache
ronaldbarendse Mar 23, 2022
2d4a058
Update icon.png include
ronaldbarendse Mar 29, 2022
f5e2e40
Update to latest Umbraco v10 preview
ronaldbarendse Apr 13, 2022
87cca72
Add comment about CLSCompliantAttribute
ronaldbarendse Apr 13, 2022
77e2dc0
Remove redundant code and calls in DI extension methods
ronaldbarendse Apr 13, 2022
01bb12f
Ensure RemoveMediaFromPath also removes customized media path
ronaldbarendse Apr 13, 2022
016f849
Code cleanup (seal classes, parameter null checking, expression bodies)
ronaldbarendse Apr 13, 2022
2be5ee6
Change AnalysisMode to .NET 6 value for all
ronaldbarendse Apr 14, 2022
dc2b1e2
Install PublicApiAnalyzers and update editorconfig
ronaldbarendse Apr 14, 2022
ce61fbf
Install StyleCop.Analyzers and update code styling/documentation
ronaldbarendse Apr 14, 2022
fd349a4
Update dependency versions and fix nullability issues
ronaldbarendse May 9, 2022
22bf9a4
Re-add updated Nerdbank.GitVersioning dependency
ronaldbarendse May 9, 2022
6c1e7bf
Remove nightly MyGet feed
ronaldbarendse May 9, 2022
80f4d14
Revert GitVersioning and PublicApiAnalyzers
ronaldbarendse May 11, 2022
e2b8943
Remove version.json from solution items
ronaldbarendse May 11, 2022
8f19fff
Fix typos in README.md
ronaldbarendse May 11, 2022
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
122 changes: 106 additions & 16 deletions .editorconfig
100755 → 100644
Original file line number Diff line number Diff line change
@@ -1,21 +1,55 @@
# editorconfig.org

# top-most EditorConfig file
root = true

# Default settings:
# A newline ending every file
# Use 4 spaces as indentation
[*]
insert_final_newline = true
end_of_line = lf
indent_style = space
indent_size = 4

# Trim trailing whitespace, limited support.
# https://github.com/editorconfig/editorconfig/wiki/Property-research:-Trim-trailing-spaces
trim_trailing_whitespace = true

csharp_indent_braces = false
csharp_indent_case_contents = true
csharp_indent_labels = one_less_than_current
csharp_prefer_braces = true:warning
csharp_prefer_simple_default_expression = true:suggestion
csharp_prefer_simple_using_statement = true:suggestion
csharp_prefer_static_local_function = true:suggestion
csharp_space_around_binary_operators = before_and_after
csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true:silent
csharp_style_allow_blank_lines_between_consecutive_braces_experimental = true:silent
csharp_style_allow_embedded_statements_on_same_line_experimental = true:silent
csharp_style_conditional_delegate_call = true:suggestion
csharp_style_deconstructed_variable_declaration = true:suggestion
csharp_style_expression_bodied_accessors = true:silent
csharp_style_expression_bodied_constructors = true:silent
csharp_style_expression_bodied_indexers = true:silent
csharp_style_expression_bodied_lambdas = true:silent
csharp_style_expression_bodied_local_functions = false:silent
csharp_style_expression_bodied_methods = true:silent
csharp_style_expression_bodied_operators = true:silent
csharp_style_expression_bodied_properties = true:silent
csharp_style_implicit_object_creation_when_type_is_apparent = true:suggestion
csharp_style_inlined_variable_declaration = true:suggestion
csharp_style_namespace_declarations = block_scoped:silent
csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
csharp_style_prefer_extended_property_pattern = true:suggestion
csharp_style_prefer_index_operator = true:suggestion
csharp_style_prefer_local_over_anonymous_function = true:suggestion
csharp_style_prefer_not_pattern = true:suggestion
csharp_style_prefer_null_check_over_type_check = true:suggestion
csharp_style_prefer_pattern_matching = true:silent
csharp_style_prefer_range_operator = true:suggestion
csharp_style_prefer_switch_expression = true:suggestion
csharp_style_prefer_tuple_swap = true:suggestion
csharp_style_throw_expression = true:suggestion
csharp_style_unused_value_assignment_preference = discard_variable:suggestion
csharp_style_unused_value_expression_statement_preference = discard_variable:silent
csharp_style_var_elsewhere = false:silent
csharp_style_var_for_built_in_types = false:silent
csharp_style_var_when_type_is_apparent = false:silent
csharp_using_directive_placement = outside_namespace:silent

[*.md]
insert_final_newline = false
trim_trailing_whitespace = false
Expand All @@ -24,14 +58,70 @@ trim_trailing_whitespace = false
indent_size = 2

[*.{cs,vb}]
dotnet_style_predefined_type_for_locals_parameters_members = true:error
tab_width = 4

dotnet_naming_rule.private_members_with_underscore.symbols = private_fields
dotnet_naming_rule.private_members_with_underscore.style = prefix_underscore
dotnet_code_quality_unused_parameters = all:suggestion
dotnet_naming_rule.private_members_with_underscore.severity = suggestion

dotnet_naming_symbols.private_fields.applicable_kinds = field
dotnet_naming_symbols.private_fields.applicable_accessibilities = private

dotnet_naming_rule.private_members_with_underscore.style = prefix_underscore
dotnet_naming_rule.private_members_with_underscore.symbols = private_fields
dotnet_naming_style.prefix_underscore.capitalization = camel_case
dotnet_naming_style.prefix_underscore.required_prefix = _
dotnet_naming_symbols.private_fields.applicable_accessibilities = private
dotnet_naming_symbols.private_fields.applicable_kinds = field
dotnet_style_allow_multiple_blank_lines_experimental = true:silent
dotnet_style_allow_statement_immediately_after_block_experimental = true:silent
dotnet_style_coalesce_expression = true:suggestion
dotnet_style_collection_initializer = true:suggestion
dotnet_style_explicit_tuple_names = true:suggestion
dotnet_style_namespace_match_folder = true:suggestion
dotnet_style_null_propagation = true:suggestion
dotnet_style_object_initializer = true:suggestion
dotnet_style_operator_placement_when_wrapping = beginning_of_line
dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent
dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent
dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent
dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent
dotnet_style_predefined_type_for_locals_parameters_members = true:error
dotnet_style_predefined_type_for_member_access = true:silent
dotnet_style_prefer_auto_properties = true:silent
dotnet_style_prefer_compound_assignment = true:suggestion
dotnet_style_prefer_conditional_expression_over_assignment = true:silent
dotnet_style_prefer_conditional_expression_over_return = true:silent
dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
dotnet_style_prefer_inferred_tuple_names = true:suggestion
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion
dotnet_style_prefer_simplified_boolean_expressions = true:suggestion
dotnet_style_prefer_simplified_interpolation = true:suggestion
dotnet_style_qualification_for_event = false:silent
dotnet_style_qualification_for_field = false:silent
dotnet_style_qualification_for_method = false:silent
dotnet_style_qualification_for_property = false:silent
dotnet_style_readonly_field = true:suggestion
dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent

# CA1054: URI parameters should not be strings
dotnet_diagnostic.CA1054.severity = suggestion

# CA1055: URI-like return values should not be strings
dotnet_diagnostic.CA1055.severity = none

# RS0048: Missing shipped or unshipped public API file
dotnet_public_api_analyzer.require_api_files = true

# SA1101: Prefix local calls with this
dotnet_diagnostic.SA1101.severity = none

# SA1309: Field names should not begin with underscore
dotnet_diagnostic.SA1309.severity = none

# SA1413: Use trailing comma in multi-line initializers
dotnet_diagnostic.SA1413.severity = none

# SA1502: Element should not be on a single line
dotnet_diagnostic.SA1502.severity = none

# SA1625: Element documentation should not be copied and pasted
dotnet_diagnostic.SA1625.severity = none

# SA1633: File should have header
dotnet_diagnostic.SA1633.severity = none
8 changes: 0 additions & 8 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
*.dll
*.exe
*.log
*.nupkg
*.suo
*.user

Expand All @@ -10,7 +6,3 @@
.vscode/
[Bb]in/
[Oo]bj/

Build/temp
build.out/
build.tmp/
8 changes: 0 additions & 8 deletions NuGet.config

This file was deleted.

113 changes: 60 additions & 53 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,73 +1,84 @@
# Umbraco.StorageProviders
# Umbraco storage providers

This repository contains Umbraco storage providers that can replace the default physical file storage.

## Umbraco.StorageProviders.AzureBlob

The Azure Blob Storage provider has an implementation of the Umbraco `IFileSystem` that connects to an Azure Blob Storage container.
## Umbraco.StorageProviders

It also has the following features:
- middleware for serving media files from the `/media` path
- ImageSharp image provider/cache
- a CDN media URL provider
Contains shared storage providers infrastructure, like a CDN media URL provider.

### Usage

This provider can be added in the `Startup.cs` file:

```csharp
public void ConfigureServices(IServiceCollection services)
{
services.AddUmbraco(_env, _config)
.AddBackOffice()
.AddWebsite()
.AddComposers()
// Add the Azure Blob Storage file system, ImageSharp image provider/cache and middleware for Media:
.AddAzureBlobMediaFileSystem()
// Optionally add the CDN media URL provider:
// Add the CDN media URL provider:
.AddCdnMediaUrlProvider()
.Build();
}
```

There are multiple ways to configure the CDN provider. It can be done in code:

```csharp
.AddCdnMediaUrlProvider(options => {
options.Url = new Uri("https://cdn.example.com/");
});
```

In `appsettings.json`:

public void Configure(IApplicationBuilder app)
```json
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
"Umbraco": {
"Storage": {
"Cdn": {
"Url": "https://cdn.example.com/"
}
}

app.UseUmbraco()
.WithMiddleware(u =>
{
u.UseBackOffice();
u.UseWebsite();
// Enables the Azure Blob Storage middleware for Media:
u.UseAzureBlobMediaFileSystem();

})
.WithEndpoints(u =>
{
u.UseInstallerEndpoints();
u.UseBackOfficeEndpoints();
u.UseWebsiteEndpoints();
});
}
}
```

There're multiple ways to configure the provider, it can be done in code:
Or by environment variables:

```csharp
services.AddUmbraco(_env, _config)
```sh
UMBRACO__STORAGE__CDN__URL=<CDN_BASE_URL>
```

.AddAzureBlobMediaFileSystem(options => {
options.ConnectionString = "";
options.ContainerName = "";
})
_Note: you still have to add the provider in the `Startup.cs` file when not configuring the options in code._

.AddCdnMediaUrlProvider(options => {
options.Url = new Uri("https://my-cdn.example.com/");
});
## Umbraco.StorageProviders.AzureBlob

The Azure Blob Storage provider has an implementation of the Umbraco `IFileSystem` that connects to an Azure Blob Storage container.

### Usage

This provider can be added in the `Startup.cs` file:

```csharp
public void ConfigureServices(IServiceCollection services)
{
services.AddUmbraco(_env, _config)
.AddBackOffice()
.AddWebsite()
.AddComposers()
// Add the Azure Blob Storage file system
.AddAzureBlobMediaFileSystem()
.Build();
}
```

There are multiple ways to configure the provider. It can be done in code:

```csharp
.AddAzureBlobMediaFileSystem(options => {
options.ConnectionString = "";
options.ContainerName = "";
})
```

In `appsettings.json`:
Expand All @@ -79,10 +90,7 @@ In `appsettings.json`:
"AzureBlob": {
"Media": {
"ConnectionString": "",
"ContainerName": "",
"Cdn": {
"Url": ""
}
"ContainerName": ""
}
}
}
Expand All @@ -95,22 +103,21 @@ Or by environment variables:
```sh
UMBRACO__STORAGE__AZUREBLOB__MEDIA__CONNECTIONSTRING=<CONNECTION_STRING>
UMBRACO__STORAGE__AZUREBLOB__MEDIA__CONTAINERNAME=<CONTAINER_NAME>
UMBRACO__STORAGE__AZUREBLOB__MEDIA__CDN__URL=<CDN_BASE_URL>
```

_Note: you still have to add the provider in the `Startup.cs` file when not configuring the options in code._

## Using the file system provider

Please refer to our documentation on [using custom file systems](https://our.umbraco.com/documentation/Extending/FileSystemProviders/).

## Folder structure in the Azure Blob Storage container
### Folder structure in the Azure Blob Storage container
The container name is expected to exist and uses the following folder structure:
- `/media` - contains the Umbraco media, stored in the structure defined by the `IMediaPathScheme` registered in Umbraco (the default `UniqueMediaPathScheme` stores files with their original filename in 8 character directories, based on the content and property GUID identifier)
- `/cache` - contains the ImageSharp image cache, stored as files with a filename defined by the `ICacheHash` registered in ImageSharp (the default `CacheHash` generates SHA256 hashes of the file contents and uses the first characters configured by the `Umbraco:CMS:Imaging:CachedNameLength` setting)

Note that this is different than the behavior of other file system providers - i.e. https://github.com/umbraco-community/UmbracoFileSystemProviders.Azure that expect the media contents to be at the root level.

## Using the file system providers

Please refer to our documentation on [using custom file systems](https://our.umbraco.com/documentation/Extending/FileSystemProviders/).

## Bugs, issues and Pull Requests

If you encounter a bug when using this client library you are welcome to open an issue in the issue tracker of this repository. We always welcome Pull Request and please feel free to open an issue before submitting a Pull Request to discuss what you want to submit.
Expand Down
15 changes: 14 additions & 1 deletion Umbraco.StorageProviders.sln
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,11 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
azure-pipelines.yml = azure-pipelines.yml
src\Directory.Build.props = src\Directory.Build.props
LICENSE = LICENSE
NuGet.config = NuGet.config
README.md = README.md
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Umbraco.StorageProviders", "src\Umbraco.StorageProviders\Umbraco.StorageProviders.csproj", "{5EC38982-2C9A-4D8D-AAE2-743A690FCD71}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -39,6 +40,18 @@ Global
{99A3FCBE-FDC6-4580-BDB8-7D219C6D98C3}.Release|x64.Build.0 = Release|Any CPU
{99A3FCBE-FDC6-4580-BDB8-7D219C6D98C3}.Release|x86.ActiveCfg = Release|Any CPU
{99A3FCBE-FDC6-4580-BDB8-7D219C6D98C3}.Release|x86.Build.0 = Release|Any CPU
{5EC38982-2C9A-4D8D-AAE2-743A690FCD71}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5EC38982-2C9A-4D8D-AAE2-743A690FCD71}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5EC38982-2C9A-4D8D-AAE2-743A690FCD71}.Debug|x64.ActiveCfg = Debug|Any CPU
{5EC38982-2C9A-4D8D-AAE2-743A690FCD71}.Debug|x64.Build.0 = Debug|Any CPU
{5EC38982-2C9A-4D8D-AAE2-743A690FCD71}.Debug|x86.ActiveCfg = Debug|Any CPU
{5EC38982-2C9A-4D8D-AAE2-743A690FCD71}.Debug|x86.Build.0 = Debug|Any CPU
{5EC38982-2C9A-4D8D-AAE2-743A690FCD71}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5EC38982-2C9A-4D8D-AAE2-743A690FCD71}.Release|Any CPU.Build.0 = Release|Any CPU
{5EC38982-2C9A-4D8D-AAE2-743A690FCD71}.Release|x64.ActiveCfg = Release|Any CPU
{5EC38982-2C9A-4D8D-AAE2-743A690FCD71}.Release|x64.Build.0 = Release|Any CPU
{5EC38982-2C9A-4D8D-AAE2-743A690FCD71}.Release|x86.ActiveCfg = Release|Any CPU
{5EC38982-2C9A-4D8D-AAE2-743A690FCD71}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
Loading