diff --git a/PineBlog.sln b/PineBlog.sln
index 6c9935d..53a716a 100644
--- a/PineBlog.sln
+++ b/PineBlog.sln
@@ -58,6 +58,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "01 Docs", "01 Docs", "{5D82
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Opw.PineBlog.EntityFrameworkCore.Tests", "tests\Opw.PineBlog.EntityFrameworkCore.Tests\Opw.PineBlog.EntityFrameworkCore.Tests.csproj", "{09215473-245F-4484-B61C-7FBFC70E8C18}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Opw.PineBlog.Sample.Tests", "tests\Opw.PineBlog.Sample.Tests\Opw.PineBlog.Sample.Tests.csproj", "{FD61CF8C-B52E-4692-9B93-8D48255FD3D1}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -104,6 +106,10 @@ Global
{09215473-245F-4484-B61C-7FBFC70E8C18}.Debug|Any CPU.Build.0 = Debug|Any CPU
{09215473-245F-4484-B61C-7FBFC70E8C18}.Release|Any CPU.ActiveCfg = Release|Any CPU
{09215473-245F-4484-B61C-7FBFC70E8C18}.Release|Any CPU.Build.0 = Release|Any CPU
+ {FD61CF8C-B52E-4692-9B93-8D48255FD3D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {FD61CF8C-B52E-4692-9B93-8D48255FD3D1}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {FD61CF8C-B52E-4692-9B93-8D48255FD3D1}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {FD61CF8C-B52E-4692-9B93-8D48255FD3D1}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -119,6 +125,7 @@ Global
{49EA4528-BA74-4FE9-862D-BC1448D50EF8} = {FCEC3C6B-0FC0-42CC-AEE8-EBBC570A67A0}
{122A1302-2B62-485F-B80F-3E9210B0616F} = {64F9A954-9830-45BA-B47F-D3589072E347}
{09215473-245F-4484-B61C-7FBFC70E8C18} = {F800AFAF-471F-41F4-8F17-0C4FAEC41F6A}
+ {FD61CF8C-B52E-4692-9B93-8D48255FD3D1} = {5FEBABA0-73A1-464A-8715-19F76F742B22}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {DF018025-4A97-49F8-888F-C70856C1862A}
diff --git a/README.md b/README.md
index ae5a9cd..c6d5d4a 100644
--- a/README.md
+++ b/README.md
@@ -57,8 +57,21 @@ public void ConfigureServices(IServiceCollection services)
...
services.AddPineBlog(Configuration);
- services.AddMvc().AddPineBlogRazorPages();
+ services.AddRazorPages().AddPineBlogRazorPages();
// or services.AddMvcCore().AddPineBlogRazorPages();
+ // or services.AddMvc().AddPineBlogRazorPages();
+ ...
+}
+
+public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
+{
+ ...
+ app.UseEndpoints(endpoints =>
+ {
+ // make sure to add the endpoint mapping for both RazorPages and Controllers
+ endpoints.MapRazorPages();
+ endpoints.MapControllers();
+ });
...
}
```
diff --git a/docs/getting-started.md b/docs/getting-started.md
index 4687f4f..b815c4a 100644
--- a/docs/getting-started.md
+++ b/docs/getting-started.md
@@ -7,8 +7,21 @@ public void ConfigureServices(IServiceCollection services)
...
services.AddPineBlog(Configuration);
- services.AddMvc().AddPineBlogRazorPages();
+ services.AddRazorPages().AddPineBlogRazorPages();
// or services.AddMvcCore().AddPineBlogRazorPages();
+ // or services.AddMvc().AddPineBlogRazorPages();
+ ...
+}
+
+public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
+{
+ ...
+ app.UseEndpoints(endpoints =>
+ {
+ // make sure to add the endpoint mapping for both RazorPages and Controllers
+ endpoints.MapRazorPages();
+ endpoints.MapControllers();
+ });
...
}
```
diff --git a/samples/Opw.PineBlog.Sample/Opw.PineBlog.Sample.csproj b/samples/Opw.PineBlog.Sample/Opw.PineBlog.Sample.csproj
index 3ebde33..74e469f 100644
--- a/samples/Opw.PineBlog.Sample/Opw.PineBlog.Sample.csproj
+++ b/samples/Opw.PineBlog.Sample/Opw.PineBlog.Sample.csproj
@@ -15,7 +15,6 @@
-
diff --git a/samples/Opw.PineBlog.Sample/Program.cs b/samples/Opw.PineBlog.Sample/Program.cs
index 06ae0d7..c8c544b 100644
--- a/samples/Opw.PineBlog.Sample/Program.cs
+++ b/samples/Opw.PineBlog.Sample/Program.cs
@@ -34,9 +34,7 @@ public static void Main(string[] args)
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup()
- .ConfigureAppConfiguration((hostingContext, config) => {
- config.AddPineBlogConfiguration(reloadOnChange: true);
- })
+ .ConfigureAppConfiguration((_, config) => config.AddPineBlogConfiguration(reloadOnChange: true))
.ConfigureLogging((hostingContext, builder) =>
{
builder.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
diff --git a/samples/Opw.PineBlog.Sample/Startup.cs b/samples/Opw.PineBlog.Sample/Startup.cs
index de0ecae..54bd050 100644
--- a/samples/Opw.PineBlog.Sample/Startup.cs
+++ b/samples/Opw.PineBlog.Sample/Startup.cs
@@ -39,7 +39,8 @@ public void ConfigureServices(IServiceCollection services)
// TODO: combine with AddPineBlogRazorPages?
services.AddPineBlog(Configuration);
- services.AddRazorPages()
+ services
+ .AddRazorPages()
.SetCompatibilityVersion(CompatibilityVersion.Version_3_0)
.AddPineBlogRazorPages();
}
@@ -52,7 +53,6 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
- //TODO: app.UseDatabaseErrorPage();
}
else
{
@@ -68,7 +68,11 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
- app.UseEndpoints(endpoints => endpoints.MapRazorPages());
+ app.UseEndpoints(endpoints =>
+ {
+ endpoints.MapRazorPages();
+ endpoints.MapControllers();
+ });
}
}
}
diff --git a/tests/Opw.PineBlog.Core.Tests/Constants.cs b/tests/Opw.PineBlog.Core.Tests/Constants.cs
new file mode 100644
index 0000000..7b62755
--- /dev/null
+++ b/tests/Opw.PineBlog.Core.Tests/Constants.cs
@@ -0,0 +1,8 @@
+
+namespace Opw.PineBlog
+{
+ public static class Constants
+ {
+ public const string SkipAzureStorageEmulatorTests = "Requires Azure Storage Emulator.";
+ }
+}
diff --git a/tests/Opw.PineBlog.Core.Tests/Files/Azure/DeleteAzureBlobCommandTests.cs b/tests/Opw.PineBlog.Core.Tests/Files/Azure/DeleteAzureBlobCommandTests.cs
index 3e3fbf0..bf3d5c2 100644
--- a/tests/Opw.PineBlog.Core.Tests/Files/Azure/DeleteAzureBlobCommandTests.cs
+++ b/tests/Opw.PineBlog.Core.Tests/Files/Azure/DeleteAzureBlobCommandTests.cs
@@ -38,7 +38,7 @@ public async Task Validator_Should_ThrowValidationErrorException()
ex.Errors.Single(e => e.Key.Equals(nameof(DeleteAzureBlobCommand.FileName))).Should().NotBeNull();
}
- [Fact(Skip = "Integration Test; requires Azure Storage Emulator.")]
+ [Fact(Skip = Constants.SkipAzureStorageEmulatorTests)]
public async Task Handler_Should_ReturnTrue()
{
await Mediator.Send(new UploadAzureBlobCommand { File = _formFileMock.Object, TargetPath = "files", AllowedFileType = FileType.All });
@@ -48,7 +48,7 @@ public async Task Handler_Should_ReturnTrue()
result.IsSuccess.Should().BeTrue();
}
- [Fact(Skip = "Integration Test; requires Azure Storage Emulator.")]
+ [Fact(Skip = Constants.SkipAzureStorageEmulatorTests)]
public async Task Handler_Should_ReturnFalse_WhenFileDoesNotExist()
{
var result = await Mediator.Send(new DeleteAzureBlobCommand { FileName = "invalid-filename.txt", TargetPath = "files" });
diff --git a/tests/Opw.PineBlog.Core.Tests/Files/Azure/GetPagedAzureBlobListQueryTest.cs b/tests/Opw.PineBlog.Core.Tests/Files/Azure/GetPagedAzureBlobListQueryTest.cs
index cb09ac3..e8267d2 100644
--- a/tests/Opw.PineBlog.Core.Tests/Files/Azure/GetPagedAzureBlobListQueryTest.cs
+++ b/tests/Opw.PineBlog.Core.Tests/Files/Azure/GetPagedAzureBlobListQueryTest.cs
@@ -10,7 +10,7 @@ namespace Opw.PineBlog.Files.Azure
{
public class GetPagedAzureBlobListQueryTest : MediatRTestsBase
{
- [Fact(Skip = "Integration Test; requires Azure Storage Emulator.")]
+ [Fact(Skip = Constants.SkipAzureStorageEmulatorTests)]
public async Task Handler_Should_ReturnFirstPageWith5Files()
{
var directory = $"{DateTime.UtcNow.Ticks}-{Guid.NewGuid()}";
@@ -28,7 +28,7 @@ public async Task Handler_Should_ReturnFirstPageWith5Files()
result.Value.Pager.Total.Should().Be(9);
}
- [Fact(Skip = "Integration Test; requires Azure Storage Emulator.")]
+ [Fact(Skip = Constants.SkipAzureStorageEmulatorTests)]
public async Task Handler_Should_ReturnSecondPageWith4Files()
{
var directory = $"{DateTime.UtcNow.Ticks}-{Guid.NewGuid()}";
@@ -46,7 +46,7 @@ public async Task Handler_Should_ReturnSecondPageWith4Files()
result.Value.Pager.Total.Should().Be(9);
}
- [Fact(Skip = "Integration Test; requires Azure Storage Emulator.")]
+ [Fact(Skip = Constants.SkipAzureStorageEmulatorTests)]
public async Task Handler_Should_Return3Files_ForFileTypeImage()
{
var directory = $"{DateTime.UtcNow.Ticks}-{Guid.NewGuid()}";
diff --git a/tests/Opw.PineBlog.Core.Tests/Files/Azure/UploadAzureBlobCommandTests.cs b/tests/Opw.PineBlog.Core.Tests/Files/Azure/UploadAzureBlobCommandTests.cs
index 109da64..2df543b 100644
--- a/tests/Opw.PineBlog.Core.Tests/Files/Azure/UploadAzureBlobCommandTests.cs
+++ b/tests/Opw.PineBlog.Core.Tests/Files/Azure/UploadAzureBlobCommandTests.cs
@@ -39,7 +39,7 @@ public async Task Validator_Should_ThrowValidationErrorException()
ex.Errors.Single(e => e.Key.Equals(nameof(UploadAzureBlobCommand.AllowedFileType))).Should().NotBeNull();
}
- [Fact(Skip = "Integration Test; requires Azure Storage Emulator.")]
+ [Fact(Skip = Constants.SkipAzureStorageEmulatorTests)]
public async Task Handler_Should_ReturnTrue()
{
var result = await Mediator.Send(new UploadAzureBlobCommand { File = _formFileMock.Object, TargetPath = "files", AllowedFileType = FileType.All });
diff --git a/tests/Opw.PineBlog.Sample.Tests/Controllers/FileControllerTests.cs b/tests/Opw.PineBlog.Sample.Tests/Controllers/FileControllerTests.cs
new file mode 100644
index 0000000..ce1dff8
--- /dev/null
+++ b/tests/Opw.PineBlog.Sample.Tests/Controllers/FileControllerTests.cs
@@ -0,0 +1,30 @@
+using Newtonsoft.Json;
+using Opw.PineBlog.Models;
+using System;
+using System.Collections.Generic;
+using System.Net.Http;
+using System.Text;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace Opw.PineBlog.Sample.Controllers
+{
+ public class FileControllerTests : IClassFixture
+ {
+ private readonly TestWebApplicationFactory _factory;
+ private readonly HttpClient _client;
+
+ public FileControllerTests(TestWebApplicationFactory factory)
+ {
+ _factory = factory;
+ _client = _factory.CreateClient();
+ }
+
+ [Fact]
+ public async Task Get_Should_BeFound()
+ {
+ var response = await _client.GetAsync("admin/file");
+ response.EnsureSuccessStatusCode();
+ }
+ }
+}
diff --git a/tests/Opw.PineBlog.Sample.Tests/Opw.PineBlog.Sample.Tests.csproj b/tests/Opw.PineBlog.Sample.Tests/Opw.PineBlog.Sample.Tests.csproj
new file mode 100644
index 0000000..c976181
--- /dev/null
+++ b/tests/Opw.PineBlog.Sample.Tests/Opw.PineBlog.Sample.Tests.csproj
@@ -0,0 +1,37 @@
+
+
+
+ netcoreapp3.0;netcoreapp3.1
+ false
+ Opw.PineBlog.Sample
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Always
+
+
+
+
diff --git a/tests/Opw.PineBlog.Sample.Tests/TestWebApplicationFactory.cs b/tests/Opw.PineBlog.Sample.Tests/TestWebApplicationFactory.cs
new file mode 100644
index 0000000..ef145a4
--- /dev/null
+++ b/tests/Opw.PineBlog.Sample.Tests/TestWebApplicationFactory.cs
@@ -0,0 +1,35 @@
+using System;
+using System.Net.Http;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Mvc.Testing;
+using Microsoft.Extensions.Configuration;
+using Opw.PineBlog.EntityFrameworkCore;
+
+namespace Opw.PineBlog.Sample
+{
+ public class TestWebApplicationFactory : WebApplicationFactory
+ {
+ public IConfigurationRoot Configuration { get; }
+
+ public TestWebApplicationFactory()
+ {
+ Configuration = new ConfigurationBuilder()
+ .AddJsonFile("appsettings.json")
+ .Build();
+ }
+
+ protected override IWebHostBuilder CreateWebHostBuilder()
+ {
+ return new WebHostBuilder()
+ .UseConfiguration(Configuration)
+ .UseStartup()
+ .ConfigureAppConfiguration((_, config) => config.AddPineBlogConfiguration(reloadOnChange: true));
+ }
+
+ //public new HttpClient CreateClient()
+ //{
+ // var baseAddress = new Uri($"http://localhost/");
+ // return CreateClient(new WebApplicationFactoryClientOptions { BaseAddress = baseAddress });
+ //}
+ }
+}
diff --git a/tests/Opw.PineBlog.Sample.Tests/appsettings.json b/tests/Opw.PineBlog.Sample.Tests/appsettings.json
new file mode 100644
index 0000000..1e47629
--- /dev/null
+++ b/tests/Opw.PineBlog.Sample.Tests/appsettings.json
@@ -0,0 +1,28 @@
+{
+ "ConnectionStrings": {
+ "DefaultConnection": "Server=inMemory; Database=pineblog-db;"
+ },
+ "PineBlogOptions": {
+ "Title": "PineBlog",
+ "Description": "A blogging engine based on ASP.NET Core MVC Razor Pages and Entity Framework Core",
+ "CoverUrl": "/images/woods.gif",
+ "CoverCaption": "Battle background for the Misty Woods in the game Shadows of Adam by Tim Wendorf",
+ "CoverLink": "http://pixeljoint.com/pixelart/94359.htm",
+ "ItemsPerPage": 2,
+ "CreateAndSeedDatabases": true,
+ "ConnectionStringName": "DefaultConnection",
+ "AzureStorageConnectionString": "UseDevelopmentStorage=true",
+ "AzureStorageBlobContainerName": "pineblog",
+ "FileBaseUrl": "http://127.0.0.1:10000/devstoreaccount1"
+ },
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information"
+ }
+ },
+ "AllowedHosts": "*",
+ "StopApplicationPath": "/stop-app",
+ "ApplicationInsights": {
+ "InstrumentationKey": null
+ }
+}
\ No newline at end of file