diff --git a/.azure-pipelines/azure-pipelines.yml b/.azure-pipelines/azure-pipelines.yml
new file mode 100644
index 0000000..036e6db
--- /dev/null
+++ b/.azure-pipelines/azure-pipelines.yml
@@ -0,0 +1,167 @@
+# ASP.NET Core
+# Build and test ASP.NET Core projects targeting .NET Core.
+# Add steps that run tests, create a NuGet package, deploy, and more:
+# https://docs.microsoft.com/azure/devops/pipelines/languages/dotnet-core
+
+# name: $(majorVersion).$(minorVersion).$(patchVersion)$(channelVersion)$(buildVersion)$(Rev:.r)
+
+trigger:
+ branches:
+ include:
+ - master
+ tags:
+ include:
+ - v*
+
+pool:
+ vmImage: "ubuntu-18.04"
+
+variables:
+ buildConfiguration: "Release"
+ projectName: "Mocoding.AspNetCore.ODataApi"
+ solutionFile: "odata-api.sln"
+ oDataApi: $(projectName)
+ oDataApiEasyDocDb: $(projectName).EasyDocDb
+ oDataApiEntityFramework: $(projectName).EntityFramework
+ oDataApiMongoDb: $(projectName).MongoDb
+
+stages:
+ - stage: Build
+ pool:
+ vmImage: "ubuntu-18.04"
+ jobs:
+ - job: Package
+ steps:
+ - task: UseGitVersion@5
+ displayName: "Git Version"
+ inputs:
+ versionSpec: "5.0.0"
+ useConfigFile: true
+ configFilePath: "GitVersion.yml"
+
+ - task: UseDotNet@2
+ displayName: 'Install .NET Core sdk'
+ inputs:
+ packageType: sdk
+ version: 2.0.0
+ installationPath: $(Agent.ToolsDirectory)/dotnet
+
+ - task: UseDotNet@2
+ displayName: 'Install .NET Core sdk'
+ inputs:
+ packageType: sdk
+ version: 3.1.300
+ installationPath: $(Agent.ToolsDirectory)/dotnet
+
+ - task: DotNetCoreCLI@2
+ displayName: "dotnet restore"
+ inputs:
+ command: restore
+ projects: $(solutionFile)
+
+ - task: SonarCloudPrepare@1
+ displayName: "Sonarcloud - Prepare"
+ inputs:
+ SonarCloud: 'sonarcloud'
+ organization: 'mocoding'
+ scannerMode: 'MSBuild'
+ projectKey: 'mocoding-software_odata-api'
+ extraProperties: 'sonar.cs.opencover.reportsPaths=$(Agent.TempDirectory)/coverage.opencover.xml'
+
+ - task: DotNetCoreCLI@2
+ displayName: "dotnet build"
+ inputs:
+ command: build
+ projects: $(solutionFile)
+
+ - task: DotNetCoreCLI@2
+ displayName: "dotnet test"
+ inputs:
+ command: test
+ projects: 'test/**/*.Tests.csproj'
+ arguments: "--no-build /p:SkipCodeCoverageReport=true /p:Threshold=33 /p:CoverletOutput=$(Agent.TempDirectory)/"
+
+ - task: SonarCloudAnalyze@1
+ displayName: "Sonarcloud Analyze"
+
+ - task: SonarCloudPublish@1
+ displayName: "Sonarcloud Publish"
+ inputs:
+ pollingTimeoutSec: '300'
+
+ - task: PublishCodeCoverageResults@1
+ displayName: "Public Code Coverage"
+ inputs:
+ codeCoverageTool: "Cobertura"
+ summaryFileLocation: "$(Agent.TempDirectory)/coverage.cobertura.xml"
+ condition: succeededOrFailed()
+
+ - template: pack-template.yml
+ parameters:
+ project: $(oDataApi)
+
+ - template: pack-template.yml
+ parameters:
+ project: $(oDataApiEasyDocDb)
+
+ - template: pack-template.yml
+ parameters:
+ project: $(oDataApiEntityFramework)
+
+ - template: pack-template.yml
+ parameters:
+ project: $(oDataApiMongoDb)
+
+ - task: PublishBuildArtifacts@1
+ displayName: "Publish Artifact: nupkg"
+ inputs:
+ PathtoPublish: "$(Build.StagingDirectory)"
+ ArtifactName: nupkg
+ - stage: Deploy
+ dependsOn: Build
+ condition: and(succeeded(), contains(variables['Build.Reason'], 'PullRequest'))
+ pool:
+ vmImage: "ubuntu-18.04"
+ jobs:
+ - deployment: DevBuild
+ environment: "dev-builds"
+ strategy:
+ runOnce:
+ deploy:
+ steps:
+ - task: NuGetCommand@2
+ displayName: "Publish to nuget (dev-builds)"
+ inputs:
+ command: 'push'
+ packagesToPush: '$(Pipeline.Workspace)/**/*.nupkg;'
+ nuGetFeedType: 'internal'
+ publishVstsFeed: 'da7703d4-fb22-4933-b869-83f4264b7b84/e1336e71-3540-4a0c-830c-639112685b07'
+ allowPackageConflicts: true
+ - stage: Release
+ dependsOn: Build
+ condition: and(succeeded(), contains(variables['Build.SourceBranch'], 'tags/v'))
+ pool:
+ vmImage: "ubuntu-18.04"
+ jobs:
+ - deployment: Public
+ environment: "public"
+ strategy:
+ runOnce:
+ deploy:
+ steps:
+ - task: NuGetCommand@2
+ displayName: "Publish"
+ inputs:
+ command: 'push'
+ packagesToPush: '$(Pipeline.Workspace)/**/*.nupkg;'
+ nuGetFeedType: 'external'
+ publishFeedCredentials: 'public-nuget'
+ - task: GitHubRelease@1
+ displayName: 'Update GitHub release'
+ inputs:
+ gitHubConnection: 'mocoding-software'
+ repositoryName: 'mocoding-software/odata-api'
+ action: edit
+ tag: 'v$(Build.BuildNumber)'
+ assets: '$(Pipeline.Workspace)/**/*.nupkg'
+ assetUploadMode: replace
diff --git a/.azure-pipelines/pack-template.yml b/.azure-pipelines/pack-template.yml
new file mode 100644
index 0000000..d827ef7
--- /dev/null
+++ b/.azure-pipelines/pack-template.yml
@@ -0,0 +1,13 @@
+parameters:
+ - name: project
+ type: string
+ default: ""
+steps:
+ - task: DotNetCoreCLI@2
+ displayName: "dotnet pack ${{ parameters.project }}"
+ inputs:
+ command: pack
+ packagesToPack: "src/${{ parameters.project }}/${{ parameters.project }}.csproj"
+ configuration: $(buildConfiguration)
+ packDirectory: "$(Build.StagingDirectory)/${{ parameters.project }}"
+ buildProperties: "Version=$(Build.BuildNumber)"
diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
new file mode 100644
index 0000000..29effd7
--- /dev/null
+++ b/.devcontainer/devcontainer.json
@@ -0,0 +1,50 @@
+// If you want to run as a non-root user in the container, see .devcontainer/docker-compose.yml.
+{
+ "name": "Existing Docker Compose (Extend)",
+
+ // Update the 'dockerComposeFile' list if you have more compose files or use different names.
+ // The .devcontainer/docker-compose.yml file contains any overrides you need/want to make.
+ "dockerComposeFile": [
+ "docker-compose.yml"
+ ],
+
+ // The 'service' property is the name of the service for the container that VS Code should
+ // use. Update this value and .devcontainer/docker-compose.yml to the real service name.
+ "service": "devbox",
+
+ // The optional 'workspaceFolder' property is the path VS Code should open by default when
+ // connected. This is typically a file mount in .devcontainer/docker-compose.yml
+ "workspaceFolder": "/workspace",
+
+ // Use 'settings' to set *default* container specific settings.json values on container create.
+ // You can edit these settings after create using File > Preferences > Settings > Remote.
+ "settings": {
+ // This will ignore your local shell user setting for Linux since shells like zsh are typically
+ // not in base container images. You can also update this to an specific shell to ensure VS Code
+ // uses the right one for terminals and tasks. For example, /bin/bash (or /bin/ash for Alpine).
+ "terminal.integrated.shell.linux": null
+ },
+
+ // Uncomment the next line to have VS Code connect as an existing non-root user in the container. See
+ // https://aka.ms/vscode-remote/containers/non-root for details on adding a non-root user if none exist.
+ // "remoteUser": "vscode",
+
+ // Uncomment the next line if you want start specific services in your Docker Compose config.
+ // "runServices": [],
+
+ // Uncomment the next line if you want to keep your containers running after VS Code shuts down.
+ // "shutdownAction": "none",
+
+ // Uncomment the next line to run commands after the container is created - for example installing git.
+ "postCreateCommand": "apt-get update && apt-get install -y git",
+
+ // Add the IDs of extensions you want installed when the container is created in the array below.
+ "extensions": [
+ "ms-vscode.csharp",
+ "fudge.auto-using",
+ "formulahendry.dotnet-test-explorer",
+ "tintoy.msbuild-project-tools",
+ "eamodio.gitlens",
+ "christian-kohler.path-intellisense"
+ ]
+}
diff --git a/.devcontainer/docker-compose.yml b/.devcontainer/docker-compose.yml
new file mode 100644
index 0000000..f4a46f6
--- /dev/null
+++ b/.devcontainer/docker-compose.yml
@@ -0,0 +1,44 @@
+#-------------------------------------------------------------------------------------------------------------
+# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
+#-------------------------------------------------------------------------------------------------------------
+
+version: '2.4'
+services:
+ # Update this to the name of the service you want to work with in your docker-compose.yml file
+ devbox:
+ image: mcr.microsoft.com/dotnet/core/sdk:3.1.300
+ # You may want to add a non-root user to your Dockerfile and uncomment the line below
+ # to cause all processes to run as this user. Once present, you can also simply
+ # use the "remoteUser" property in devcontainer.json if you just want VS Code and
+ # its sub-processes (terminals, tasks, debugging) to execute as the user. On Linux,
+ # you may need to ensure the UID and GID of the container user you create matches your
+ # local user. See https://aka.ms/vscode-remote/containers/non-root for details.
+ # user: vscode
+
+ # Uncomment if you want to add a different Dockerfile in the .devcontainer folder
+ # build:
+ # context: .
+ # dockerfile: Dockerfile
+
+ # Uncomment if you want to expose any additional ports. The snippet below exposes port 3000.
+ ports:
+ - 5001:5001
+ - 5002:5002
+
+ volumes:
+ # Update this to wherever you want VS Code to mount the folder of your project
+ - ..:/workspace
+
+ # Uncomment the next line to use Docker from inside the container. See https://aka.ms/vscode-remote/samples/docker-in-docker-compose for details.
+ # - /var/run/docker.sock:/var/run/docker.sock
+
+ # Uncomment the next four lines if you will use a ptrace-based debugger like C++, Go, and Rust.
+ # cap_add:
+ # - SYS_PTRACE
+ # security_opt:
+ # - seccomp:unconfined
+
+ # Overrides default command so things don't shut down after the process ends.
+ command: /bin/sh -c "while sleep 1000; do :; done"
+
diff --git a/.gitignore b/.gitignore
index 44f26b6..978460e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,24 +1,7 @@
-## Ignore Visual Studio temporary files, build results, and
-## files generated by popular Visual Studio add-ons.
-
-# User-specific files
-*.suo
-*.user
-*.sln.docstates
*.lock.json
-.vs
-
-src/Portal/dist
-src/Portal/.tmp
-src/Portal/bin
-src/Portal/obj
-src/Portal.VsoPlugin/bin
-src/Portal.VsoPlugin/obj
-node_modules
-src/Portal/wwwroot/lib
-Debug
-Views
-data
-test_data
+*.user
bin
obj
+.vs
+.codecov
+coverage.*.xml
diff --git a/Directory.Build.props b/Directory.Build.props
new file mode 100644
index 0000000..a9db951
--- /dev/null
+++ b/Directory.Build.props
@@ -0,0 +1,11 @@
+
+
+
+ false
+ cobertura,opencover
+ [*.ODataApi]*,[*.ODataApi.*]*
+ true
+ line
+ total
+
+
diff --git a/Directory.Build.targets b/Directory.Build.targets
new file mode 100644
index 0000000..7db3cac
--- /dev/null
+++ b/Directory.Build.targets
@@ -0,0 +1,14 @@
+
+
+
+
+ all
+
+
+
+
+
+
+
+
+
diff --git a/GitVersion.yml b/GitVersion.yml
new file mode 100644
index 0000000..7224e93
--- /dev/null
+++ b/GitVersion.yml
@@ -0,0 +1,30 @@
+assembly-versioning-scheme: Major
+mode: ContinuousDeployment
+next-version: 3.0.0
+increment: Patch
+legacy-semver-padding: 1
+build-metadata-padding: 1
+commits-since-version-source-padding: 1
+continuous-delivery-fallback-tag: 'ci'
+branches:
+ master:
+ regex: master
+ mode: ContinuousDeployment
+ tag: ''
+ increment: inherit
+ prevent-increment-of-merged-branch-version: true
+ tag-number-pattern: '[/-](?\d+)[-/]'
+ pull-request:
+ regex: (pull|pull\-requests|pr)[/-]
+ mode: ContinuousDeployment
+ tag: "dev"
+ increment: Patch
+ tag-number-pattern: '[/-](?\d+)[-/]'
+ develop:
+ regex: (!master)?
+ mode: ContinuousDeployment
+ tag: useBranchName
+ increment: Patch
+ignore:
+ sha: []
+merge-message-formats: {}
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..f6df786
--- /dev/null
+++ b/README.md
@@ -0,0 +1,14 @@
+# Mocoding Stack - OData API
+
+[](https://www.nuget.org/packages/Mocoding.AspNetCore.ODataApi)
+[![Build Status][azure-pipelines]][azure-pipelines-url]
+[![Coverage][sonar-coverage]][sonar-url]
+
+
+
+[azure-pipelines]: https://dev.azure.com/mocoding/GitHub/_apis/build/status/mocoding-software.odata-api?branchName=master
+[azure-pipelines-url]: https://dev.azure.com/mocoding/GitHub/_build/latest?definitionId=115&branchName=master
+
+[sonar-url]: https://sonarcloud.io/dashboard?id=mocoding-software_odata-api
+
+[sonar-coverage]: https://sonarcloud.io/api/project_badges/measure?project=mocoding-software_odata-api&metric=coverage
diff --git a/_stylecop/StyleCop.ruleset b/StyleCop.ruleset
similarity index 95%
rename from _stylecop/StyleCop.ruleset
rename to StyleCop.ruleset
index eae2d74..31a6bd2 100644
--- a/_stylecop/StyleCop.ruleset
+++ b/StyleCop.ruleset
@@ -16,7 +16,7 @@
-
+
\ No newline at end of file
diff --git a/examples/WebApp.EF/Program.cs b/examples/WebApp.EF/Program.cs
index c140379..b2cf999 100644
--- a/examples/WebApp.EF/Program.cs
+++ b/examples/WebApp.EF/Program.cs
@@ -19,6 +19,7 @@ public static void Main(string[] args)
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
+ .UseUrls("http://localhost:5002")
.UseStartup();
}
}
diff --git a/examples/WebApp.EF/Properties/launchSettings.json b/examples/WebApp.EF/Properties/launchSettings.json
index dac0716..9badb54 100644
--- a/examples/WebApp.EF/Properties/launchSettings.json
+++ b/examples/WebApp.EF/Properties/launchSettings.json
@@ -1,11 +1,10 @@
{
"profiles": {
"WebApp.EF": {
- "commandName": "Project",
- "applicationUrl": "https://localhost:5001;http://localhost:5000",
+ "commandName": "Project",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
-}
\ No newline at end of file
+}
diff --git a/examples/WebApp.EF/Startup.cs b/examples/WebApp.EF/Startup.cs
index 99f5b08..577bfd5 100644
--- a/examples/WebApp.EF/Startup.cs
+++ b/examples/WebApp.EF/Startup.cs
@@ -1,15 +1,9 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
-using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
-using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Mocoding.AspNetCore.ODataApi;
using Mocoding.AspNetCore.ODataApi.EntityFramework;
-using Newtonsoft.Json.Serialization;
using WebApp.EF.Models;
namespace WebApp.EF
@@ -20,17 +14,14 @@ public class Startup
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
- services.AddDbContext(options =>
+ services.AddEntityFrameworkGenericRepository(options =>
options.UseSqlServer("Server=.;Database=EmDb;User=sa;Password="));
services
.AddMvcCore()
- .AddJsonFormatters(settings => settings.ContractResolver = new CamelCasePropertyNamesContractResolver())
.AddApiExplorer()
.AddODataApi()
- .AddEntityFramework();
-
-
+ .AddResources();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
@@ -41,7 +32,7 @@ public void Configure(IApplicationBuilder app, IHostingEnvironment env)
app.UseDeveloperExceptionPage();
}
- app.UseMvc(builder => builder.UseOData(app));
+ app.UseODataApi();
}
}
}
diff --git a/examples/WebApp.EF/WebApp.EF.csproj b/examples/WebApp.EF/WebApp.EF.csproj
index b7e504a..d60dca0 100644
--- a/examples/WebApp.EF/WebApp.EF.csproj
+++ b/examples/WebApp.EF/WebApp.EF.csproj
@@ -1,7 +1,7 @@
- netcoreapp2.1
+ netcoreapp3.1
@@ -10,7 +10,7 @@
-
+
diff --git a/examples/WebApp/Program.cs b/examples/WebApp/Program.cs
index f868c76..5eb05ed 100644
--- a/examples/WebApp/Program.cs
+++ b/examples/WebApp/Program.cs
@@ -12,7 +12,7 @@ public static void Main(string[] args)
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
- .UseUrls("http://localhost:5002")
+ .UseUrls("http://localhost:5001")
.UseStartup()
.Build();
}
diff --git a/examples/WebApp/Startup.cs b/examples/WebApp/Startup.cs
index f474c03..a4390c2 100644
--- a/examples/WebApp/Startup.cs
+++ b/examples/WebApp/Startup.cs
@@ -1,12 +1,13 @@
using System;
-using Microsoft.AspNet.OData.Builder;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Mocoding.AspNetCore.ODataApi;
using Mocoding.AspNetCore.ODataApi.EasyDocDb;
-using Newtonsoft.Json.Serialization;
+using Mocoding.EasyDocDb;
+using Mocoding.EasyDocDb.FileSystem;
+using Mocoding.EasyDocDb.Json;
namespace WebApp
{
@@ -23,30 +24,21 @@ public Startup(IConfiguration configuration)
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
- services.AddMvc();
services
+ .AddSingleton()
+ .AddSingleton()
+ .AddEasyDocDbGenericRepository(options => options.Connection = "../data")
.AddMvcCore()
- .AddJsonFormatters(settings => settings.ContractResolver = new CamelCasePropertyNamesContractResolver())
- .AddApiExplorer()
.AddODataApi()
- .AddEasyDocDb()
.AddResource()
.AddResource("Roles") // custom Entity Name / Url
.AddResource("settings") // override controller test 1
.AddResource(); // override controller test 2
-
- services.AddSwaggerSpecification();
}
- public void Configure(IApplicationBuilder app, IHostingEnvironment env, IServiceProvider services)
+ public void Configure(IApplicationBuilder app)
{
- app.Map("/api", apiApp =>
- {
- apiApp.UseSwaggerUIAndSpec();
- apiApp.UseMvc(builder => builder.UseOData(apiApp));
- });
-
- app.UseStaticFiles();
+ app.UseODataApi();
}
}
}
\ No newline at end of file
diff --git a/examples/WebApp/Swagger.cs b/examples/WebApp/Swagger.cs
deleted file mode 100644
index bcf712f..0000000
--- a/examples/WebApp/Swagger.cs
+++ /dev/null
@@ -1,30 +0,0 @@
-using Microsoft.AspNetCore.Builder;
-using Microsoft.Extensions.DependencyInjection;
-using Swashbuckle.AspNetCore.Swagger;
-
-namespace WebApp
-{
- public static class Swagger
- {
- public static IServiceCollection AddSwaggerSpecification(this IServiceCollection services)
- {
- return services
- .AddSwaggerGen(options =>
- {
- options.SwaggerDoc("spec", new Info { Title = "Example Api", Version = "v1" });
- options.DescribeAllEnumsAsStrings();
- });
- }
-
- public static IApplicationBuilder UseSwaggerUIAndSpec(this IApplicationBuilder app)
- {
- return app
- .UseSwagger(options => options.RouteTemplate = "${documentName}")
- .UseSwaggerUI(options =>
- {
- options.RoutePrefix = "_swagger-ui";
- options.SwaggerEndpoint("/api/$spec", "Example Api");
- });
- }
- }
-}
diff --git a/examples/WebApp/WebApp.csproj b/examples/WebApp/WebApp.csproj
index 87f7b02..9da15da 100644
--- a/examples/WebApp/WebApp.csproj
+++ b/examples/WebApp/WebApp.csproj
@@ -2,16 +2,19 @@
Exe
- netcoreapp2.1
+ netcoreapp3.1
..\..\_stylecop\StyleCop.ruleset
-
-
-
+
+
+
+
- 1.0.2
+ 1.1.118
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/icon.png b/icon.png
new file mode 100644
index 0000000..b9a2fc1
Binary files /dev/null and b/icon.png differ
diff --git a/odata-api.sln b/odata-api.sln
index 4f87e63..b78a417 100644
--- a/odata-api.sln
+++ b/odata-api.sln
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 15
-VisualStudioVersion = 15.0.27130.2010
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.29613.14
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mocoding.AspNetCore.ODataApi", "src\Mocoding.AspNetCore.ODataApi\Mocoding.AspNetCore.ODataApi.csproj", "{B774558F-8838-40DD-8F84-A7A4DADE101C}"
EndProject
@@ -19,6 +19,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebApp.EF", "examples\WebAp
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mocoding.AspNetCore.ODataApi.EntityFramework", "src\Mocoding.AspNetCore.ODataApi.EntityFramework\Mocoding.AspNetCore.ODataApi.EntityFramework.csproj", "{E3D3F709-1870-47A9-AAEF-68997069875A}"
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{DC1FB735-A291-4053-8CE9-85D7D2AE7BC8}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mocoding.AspNetCore.ODataApi.Tests", "test\Mocoding.AspNetCore.ODataApi.Tests\Mocoding.AspNetCore.ODataApi.Tests.csproj", "{0528A4FF-4821-48AC-8E2E-AC20C1069A41}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -49,6 +53,10 @@ Global
{E3D3F709-1870-47A9-AAEF-68997069875A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E3D3F709-1870-47A9-AAEF-68997069875A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E3D3F709-1870-47A9-AAEF-68997069875A}.Release|Any CPU.Build.0 = Release|Any CPU
+ {0528A4FF-4821-48AC-8E2E-AC20C1069A41}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {0528A4FF-4821-48AC-8E2E-AC20C1069A41}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0528A4FF-4821-48AC-8E2E-AC20C1069A41}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {0528A4FF-4821-48AC-8E2E-AC20C1069A41}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -60,6 +68,7 @@ Global
{4F1D93E0-06F1-4E8C-A453-EAB560C6BFD0} = {5F194EF3-90C7-42E7-9A73-9B009F37ED0E}
{9E6E3B2A-DC16-4FA4-91BD-116E0C785105} = {314FF1B1-D032-485D-BA24-37B31EC48886}
{E3D3F709-1870-47A9-AAEF-68997069875A} = {5F194EF3-90C7-42E7-9A73-9B009F37ED0E}
+ {0528A4FF-4821-48AC-8E2E-AC20C1069A41} = {DC1FB735-A291-4053-8CE9-85D7D2AE7BC8}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {E92994F3-765D-4ACA-9961-F4A8CCF52A6B}
diff --git a/src/Mocoding.AspNetCore.ODataApi.EasyDocDb/CrudRepositoryProxy.cs b/src/Mocoding.AspNetCore.ODataApi.EasyDocDb/CrudRepositoryProxy.cs
index b574116..b96ae2d 100644
--- a/src/Mocoding.AspNetCore.ODataApi.EasyDocDb/CrudRepositoryProxy.cs
+++ b/src/Mocoding.AspNetCore.ODataApi.EasyDocDb/CrudRepositoryProxy.cs
@@ -1,7 +1,4 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
+using System.Linq;
using System.Threading.Tasks;
namespace Mocoding.AspNetCore.ODataApi.EasyDocDb
@@ -9,11 +6,11 @@ namespace Mocoding.AspNetCore.ODataApi.EasyDocDb
internal class CrudRepositoryProxy : ICrudRepository
where TEntity : class, new()
{
- private ICrudRepository _repository;
+ private readonly ICrudRepository _repository;
- public CrudRepositoryProxy(DocumentRepositoryFactory factory, IEntityKeyAccossor keyAccossor)
+ public CrudRepositoryProxy(DocumentRepositoryFactory factory)
{
- _repository = factory.Get(keyAccossor);
+ _repository = factory.Create();
}
public Task AddOrUpdate(TEntity entity)
diff --git a/src/Mocoding.AspNetCore.ODataApi.EasyDocDb/DocumentCollectionCrudRepository.cs b/src/Mocoding.AspNetCore.ODataApi.EasyDocDb/DocumentCollectionCrudRepository.cs
index 7e4e115..0503e71 100644
--- a/src/Mocoding.AspNetCore.ODataApi.EasyDocDb/DocumentCollectionCrudRepository.cs
+++ b/src/Mocoding.AspNetCore.ODataApi.EasyDocDb/DocumentCollectionCrudRepository.cs
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
-using System.Linq.Expressions;
using System.Threading.Tasks;
using Mocoding.EasyDocDb;
@@ -11,11 +10,11 @@ namespace Mocoding.AspNetCore.ODataApi.EasyDocDb
public class DocumentCollectionCrudRepository : ICrudRepository
where TEntity : class, new()
{
- private readonly IEntityKeyAccossor _keyAccossor;
+ private readonly IEntityKeyAccessor _keyAccessor;
- public DocumentCollectionCrudRepository(IDocumentCollection collection, IEntityKeyAccossor keyAccossor)
+ public DocumentCollectionCrudRepository(IDocumentCollection collection, IEntityKeyAccessor keyAccessor)
{
- _keyAccossor = keyAccossor;
+ _keyAccessor = keyAccessor;
Collection = collection;
}
@@ -25,7 +24,7 @@ public DocumentCollectionCrudRepository(IDocumentCollection collection,
public virtual async Task AddOrUpdate(TEntity entity)
{
- var id = _keyAccossor.GetKey(entity);
+ var id = _keyAccessor.GetKey(entity);
if (id == null)
throw new InvalidOperationException($"object key is missing");
@@ -65,6 +64,6 @@ public async Task DeleteByKey(TKey key)
// }
// }
private IDocument GetById(TKey id) => Collection.Documents.FirstOrDefault(_ =>
- EqualityComparer.Default.Equals(_keyAccossor.GetKey(_.Data), id));
+ EqualityComparer.Default.Equals(_keyAccessor.GetKey(_.Data), id));
}
}
diff --git a/src/Mocoding.AspNetCore.ODataApi.EasyDocDb/DocumentCrudRepository.cs b/src/Mocoding.AspNetCore.ODataApi.EasyDocDb/DocumentCrudRepository.cs
index 9a2969c..3cd1fdb 100644
--- a/src/Mocoding.AspNetCore.ODataApi.EasyDocDb/DocumentCrudRepository.cs
+++ b/src/Mocoding.AspNetCore.ODataApi.EasyDocDb/DocumentCrudRepository.cs
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
-using System.Linq.Expressions;
using System.Threading.Tasks;
using Mocoding.EasyDocDb;
@@ -11,12 +10,12 @@ namespace Mocoding.AspNetCore.ODataApi.EasyDocDb
public class DocumentCrudRepository : ICrudRepository
where TEntity : class
{
- private readonly IEntityKeyAccossor _keyAccossor;
+ private readonly IEntityKeyAccessor _keyAccessor;
private readonly object _lock = new object();
- public DocumentCrudRepository(IDocument> collection, IEntityKeyAccossor keyAccossor)
+ public DocumentCrudRepository(IDocument> collection, IEntityKeyAccessor keyAccessor)
{
- _keyAccossor = keyAccossor;
+ _keyAccessor = keyAccessor;
Collection = collection;
}
@@ -58,7 +57,7 @@ public async Task DeleteByKey(TKey key)
protected virtual void AddOrUpdateInternal(TEntity entity)
{
- var key = _keyAccossor.GetKey(entity);
+ var key = _keyAccessor.GetKey(entity);
if (key == null)
throw new InvalidOperationException($"object key is missing");
@@ -79,7 +78,7 @@ private Func FindByKeyPredicate(TKey key)
{
return entity =>
{
- var entityKey = _keyAccossor.GetKey(entity);
+ var entityKey = _keyAccessor.GetKey(entity);
return EqualityComparer.Default.Equals(entityKey, key);
};
}
diff --git a/src/Mocoding.AspNetCore.ODataApi.EasyDocDb/DocumentRepositoryFactory.cs b/src/Mocoding.AspNetCore.ODataApi.EasyDocDb/DocumentRepositoryFactory.cs
index 8bfc5df..99455ec 100644
--- a/src/Mocoding.AspNetCore.ODataApi.EasyDocDb/DocumentRepositoryFactory.cs
+++ b/src/Mocoding.AspNetCore.ODataApi.EasyDocDb/DocumentRepositoryFactory.cs
@@ -3,35 +3,30 @@
using System.Collections.Generic;
using System.IO;
using System.Reflection;
-
+using Microsoft.Extensions.Options;
using Mocoding.AspNetCore.ODataApi.EasyDocDb.Helpers;
using Mocoding.EasyDocDb;
-using Mocoding.EasyDocDb.FileSystem;
-using Mocoding.EasyDocDb.Json;
namespace Mocoding.AspNetCore.ODataApi.EasyDocDb
{
public class DocumentRepositoryFactory
{
+ private readonly IEntityKeyAccessor _keyAccessor;
private readonly string _conn;
private readonly IRepository _repository;
+ private readonly IDocumentSerializer _serializer;
private readonly IDictionary _crudRepositories;
- public DocumentRepositoryFactory(string conn)
- {
- _conn = conn;
- _repository = new EmbeddedRepository(new JsonSerializer());
- _crudRepositories = new ConcurrentDictionary();
- }
-
- public DocumentRepositoryFactory(string conn, IDocumentStorage storage)
+ public DocumentRepositoryFactory(IEntityKeyAccessor keyAccessor, IOptions options, IRepository repository, IDocumentSerializer serializer)
{
- _conn = conn;
- _repository = new EmbeddedRepository(new JsonSerializer(), storage);
+ _keyAccessor = keyAccessor;
+ _conn = options.Value.Connection;
+ _repository = repository;
+ _serializer = serializer;
_crudRepositories = new ConcurrentDictionary();
}
- public ICrudRepository Get(IEntityKeyAccossor keyAccossor)
+ public ICrudRepository Create()
where TEntity : class, new()
{
var t = typeof(TEntity);
@@ -41,8 +36,8 @@ public ICrudRepository Get(IEntityKeyAccossor keyA
var name = t.Name.ToLower();
var attribute = t.GetCustomAttribute(typeof(ReadOptimizedAttribute));
var repo = attribute != null
- ? new DocumentCrudRepository(_repository.Init>(Path.Combine(_conn, name + ".json")).Result, keyAccossor)
- : new DocumentCollectionCrudRepository(_repository.InitCollection(Path.Combine(_conn, name)).Result, keyAccossor) as ICrudRepository;
+ ? new DocumentCrudRepository(_repository.Init>(Path.Combine(_conn, $"{name}.{_serializer.Type}")).Result, _keyAccessor)
+ : new DocumentCollectionCrudRepository(_repository.InitCollection(Path.Combine(_conn, name)).Result, _keyAccessor) as ICrudRepository;
_crudRepositories.Add(t, repo);
diff --git a/src/Mocoding.AspNetCore.ODataApi.EasyDocDb/Extensions.cs b/src/Mocoding.AspNetCore.ODataApi.EasyDocDb/Extensions.cs
index fa0f50b..589dfef 100644
--- a/src/Mocoding.AspNetCore.ODataApi.EasyDocDb/Extensions.cs
+++ b/src/Mocoding.AspNetCore.ODataApi.EasyDocDb/Extensions.cs
@@ -1,20 +1,18 @@
-using Microsoft.Extensions.DependencyInjection.Extensions;
+using System;
+using Microsoft.Extensions.DependencyInjection;
using Mocoding.EasyDocDb;
namespace Mocoding.AspNetCore.ODataApi.EasyDocDb
{
public static class Extensions
{
- public static IODataApiBuilder AddEasyDocDb(this IODataApiBuilder oDataApiBuilder, string folder = "../data")
+ public static IServiceCollection AddEasyDocDbGenericRepository(this IServiceCollection services, Action configure)
{
- oDataApiBuilder.Services.TryAddSingleton(new DocumentRepositoryFactory(folder));
- return oDataApiBuilder;
- }
-
- public static IODataApiBuilder AddEasyDocDb(this IODataApiBuilder oDataApiBuilder, string connection, IDocumentStorage storage)
- {
- oDataApiBuilder.Services.TryAddSingleton(new DocumentRepositoryFactory(connection, storage));
- return oDataApiBuilder;
+ return services
+ .Configure(configure)
+ .AddSingleton()
+ .AddSingleton()
+ .AddSingleton(typeof(ICrudRepository<,>), typeof(CrudRepositoryProxy<,>));
}
}
}
\ No newline at end of file
diff --git a/src/Mocoding.AspNetCore.ODataApi.EasyDocDb/Mocoding.AspNetCore.ODataApi.EasyDocDb.csproj b/src/Mocoding.AspNetCore.ODataApi.EasyDocDb/Mocoding.AspNetCore.ODataApi.EasyDocDb.csproj
index 8654d8c..7e984ef 100644
--- a/src/Mocoding.AspNetCore.ODataApi.EasyDocDb/Mocoding.AspNetCore.ODataApi.EasyDocDb.csproj
+++ b/src/Mocoding.AspNetCore.ODataApi.EasyDocDb/Mocoding.AspNetCore.ODataApi.EasyDocDb.csproj
@@ -1,27 +1,13 @@
-
+
+
- EasyDocDb storage provider for generic OData API implementation
- netstandard2.0
- netstandard;.net core;odata;generic;easydocdb;storage
- Initial Release.
- https://mocoding.blob.core.windows.net/resources/odata-api/nugetIcon.png
- https://github.com/mocoding-software/odata-api
- https://raw.githubusercontent.com/mocoding-software/odata-api/master/LICENSE
- git
- https://github.com/mocoding-software/odata-api
- ..\..\_stylecop\StyleCop.ruleset
- Mocoding
-
-
+ EasyDocDb storage provider for generic OData API implementation
+ netstandard;.net core;odata;generic;easydocdb;storage
+
-
-
-
- all
- 1.0.2
-
+
diff --git a/src/Mocoding.AspNetCore.ODataApi.EasyDocDb/ODataEasyDocDbOptions.cs b/src/Mocoding.AspNetCore.ODataApi.EasyDocDb/ODataEasyDocDbOptions.cs
new file mode 100644
index 0000000..ff3a5f5
--- /dev/null
+++ b/src/Mocoding.AspNetCore.ODataApi.EasyDocDb/ODataEasyDocDbOptions.cs
@@ -0,0 +1,11 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Mocoding.AspNetCore.ODataApi.EasyDocDb
+{
+ public class ODataEasyDocDbOptions
+ {
+ public string Connection { get; set; }
+ }
+}
diff --git a/src/Mocoding.AspNetCore.ODataApi.EntityFramework/CrudRepository.cs b/src/Mocoding.AspNetCore.ODataApi.EntityFramework/CrudRepository.cs
deleted file mode 100644
index 445baeb..0000000
--- a/src/Mocoding.AspNetCore.ODataApi.EntityFramework/CrudRepository.cs
+++ /dev/null
@@ -1,54 +0,0 @@
-using System;
-using System.Linq;
-using System.Linq.Expressions;
-using System.Threading.Tasks;
-using Mocoding.AspNetCore.ODataApi.DataAccess;
-
-namespace Mocoding.AspNetCore.ODataApi.EntityFramework
-{
- public class CrudRepository : ICrudRepository
- where TData : class, IEntity, new()
- {
- private readonly IMongoDatabase _database;
- private readonly string _tableName;
-
- public CrudRepository(string connectionString, string name = null)
- {
- var connection = new MongoUrlBuilder(connectionString);
- var client = new MongoClient(connectionString);
- _database = client.GetDatabase(connection.DatabaseName);
- _tableName = string.IsNullOrEmpty(name) ? typeof(TData).Name : name;
- Collection.EnsureIndexes();
- }
-
- protected IMongoCollection Collection => _database.GetCollection(_tableName);
-
- public virtual IQueryable QueryRecords() => Collection.AsQueryable();
-
- public virtual async Task AddOrUpdate(TData entity)
- {
- if (!entity.Id.HasValue)
- entity.Id = Guid.NewGuid();
-
- await Collection.ReplaceOneAsync(new BsonDocument("_id", entity.Id), entity, new UpdateOptions() { IsUpsert = true });
-
- return entity;
- }
-
- public virtual Task Delete(Guid id) => Collection.DeleteOneAsync(new BsonDocument("_id", id));
-
- public virtual Task BatchAddOrUpdate(TData[] entities)
- {
- var model = entities.Select(_ =>
- {
- if (!_.Id.HasValue)
- _.Id = Guid.NewGuid();
- return new ReplaceOneModel(new BsonDocument("_id", _.Id), _) { IsUpsert = true };
- });
-
- return Collection.BulkWriteAsync(model);
- }
-
- public virtual Task BatchDelete(Expression> predicate) => Collection.DeleteManyAsync(predicate);
- }
-}
\ No newline at end of file
diff --git a/src/Mocoding.AspNetCore.ODataApi.EntityFramework/DbSetRepository.cs b/src/Mocoding.AspNetCore.ODataApi.EntityFramework/DbSetRepository.cs
index 1e92907..4dde7c7 100644
--- a/src/Mocoding.AspNetCore.ODataApi.EntityFramework/DbSetRepository.cs
+++ b/src/Mocoding.AspNetCore.ODataApi.EntityFramework/DbSetRepository.cs
@@ -11,13 +11,13 @@ class DbSetRepository : ICrudRepository
{
private readonly DbSet _repository;
private readonly DbContext _context;
- private readonly IEntityKeyAccossor _keyAccossor;
+ private readonly IEntityKeyAccessor _keyAccessor;
- public DbSetRepository(DbContext context, IEntityKeyAccossor keyAccossor)
+ public DbSetRepository(DbContext context, IEntityKeyAccessor keyAccessor)
{
_repository = context.Set();
_context = context;
- _keyAccossor = keyAccossor;
+ _keyAccessor = keyAccessor;
}
public IQueryable QueryRecords()
@@ -28,7 +28,7 @@ public IQueryable QueryRecords()
public async Task AddOrUpdate(TEntity entity)
{
// var contains = ;
- //var id = _keyAccossor.GetKey(entity);
+ //var id = _keyAccessor.GetKey(entity);
//if (id == null)
// throw new InvalidOperationException($"object key is missing");
diff --git a/src/Mocoding.AspNetCore.ODataApi.EntityFramework/Extensions.cs b/src/Mocoding.AspNetCore.ODataApi.EntityFramework/Extensions.cs
index 7093a15..880d416 100644
--- a/src/Mocoding.AspNetCore.ODataApi.EntityFramework/Extensions.cs
+++ b/src/Mocoding.AspNetCore.ODataApi.EntityFramework/Extensions.cs
@@ -1,4 +1,6 @@
-using System.Linq;
+using System;
+using System.Linq;
+using Microsoft.AspNetCore.Authentication;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Internal;
using Microsoft.Extensions.DependencyInjection;
@@ -9,24 +11,29 @@ namespace Mocoding.AspNetCore.ODataApi.EntityFramework
{
public static class Extensions
{
- public static IODataApiBuilder AddEntityFramework(this IODataApiBuilder builder) where TContext : DbContext
+ public static IODataApiBuilder AddResources(this IODataApiBuilder builder) where TContext : DbContext
{
- var serviceProvider = builder.Services.BuildServiceProvider();
- var context = serviceProvider.GetRequiredService();
var properties = typeof(TContext).GetProperties();
- var types = context.Model.GetEntityTypes();
- foreach (var entityType in types)
+ var dbSetType = typeof(DbSet<>);
+ foreach (var property in properties.Where(_=> _.PropertyType.IsGenericType && _.PropertyType.GetGenericTypeDefinition() == dbSetType))
{
- var dbSetType = typeof(DbSet<>).MakeGenericType(entityType.ClrType);
- var property = properties.FirstOrDefault(_ => _.PropertyType.IsAssignableFrom(dbSetType));
- builder.AddResource(entityType.ClrType, property != null ? property.Name.ToLower() : null);
+ var type = property.PropertyType.GenericTypeArguments[0];
+ builder.AddResource(type, property.Name.ToLower());
}
-
-
- builder.Services.TryAddTransient();
- builder.Services.TryAddScoped(typeof(ICrudRepository<,>), typeof(DbSetRepository<,>));
- return builder;
-
+
+
+ return builder;
}
+
+ public static IServiceCollection AddEntityFrameworkGenericRepository(this IServiceCollection services, Action configure)
+ where TContext : DbContext
+ {
+ services
+ .AddDbContext(configure)
+ .TryAddScoped(typeof(ICrudRepository<,>), typeof(DbSetRepository<,>));
+ return services;
+ }
+
+
}
}
diff --git a/src/Mocoding.AspNetCore.ODataApi.EntityFramework/Mocoding.AspNetCore.ODataApi.EntityFramework.csproj b/src/Mocoding.AspNetCore.ODataApi.EntityFramework/Mocoding.AspNetCore.ODataApi.EntityFramework.csproj
index 83c41d7..666b2eb 100644
--- a/src/Mocoding.AspNetCore.ODataApi.EntityFramework/Mocoding.AspNetCore.ODataApi.EntityFramework.csproj
+++ b/src/Mocoding.AspNetCore.ODataApi.EntityFramework/Mocoding.AspNetCore.ODataApi.EntityFramework.csproj
@@ -1,27 +1,13 @@
+
- EntityFramework storage provider for generic OData API implementation
- netstandard2.0
- netstandard;.net core;odata;generic;sql;mssql,mssql server,storage;
- Initial Release.
- https://mocoding.blob.core.windows.net/resources/odata-api/nugetIcon.png
- https://github.com/mocoding-software/odata-api
- https://raw.githubusercontent.com/mocoding-software/odata-api/master/LICENSE
- git
- https://github.com/mocoding-software/odata-api
- ..\..\_stylecop\StyleCop.ruleset
- Mocoding
+ EntityFramework storage provider for generic OData API implementation
+ netstandard;.net core;odata;generic;sql;mssql,mssql server,storage;
-
-
-
-
-
-
-
+
diff --git a/src/Mocoding.AspNetCore.ODataApi.MongoDb/CrudRepository.cs b/src/Mocoding.AspNetCore.ODataApi.MongoDb/CrudRepository.cs
index 0b23aac..bb038b9 100644
--- a/src/Mocoding.AspNetCore.ODataApi.MongoDb/CrudRepository.cs
+++ b/src/Mocoding.AspNetCore.ODataApi.MongoDb/CrudRepository.cs
@@ -12,13 +12,13 @@ class CrudRepository : ICrudRepository
where TEntity : class, new()
{
private readonly IMongoDatabase _database;
- private readonly IEntityKeyAccossor _keyAccossor;
+ private readonly IEntityKeyAccessor _keyAccessor;
private readonly string _tableName;
- public CrudRepository(IMongoDatabase database, IEntityKeyAccossor keyAccossor)
+ public CrudRepository(IMongoDatabase database, IEntityKeyAccessor keyAccessor)
{
_database = database;
- _keyAccossor = keyAccossor;
+ _keyAccessor = keyAccessor;
_tableName = typeof(TEntity).Name;
Collection.EnsureIndexes();
}
@@ -29,7 +29,7 @@ public CrudRepository(IMongoDatabase database, IEntityKeyAccossor keyAccossor)
public virtual async Task AddOrUpdate(TEntity entity)
{
- var id = _keyAccossor.GetKey(entity);
+ var id = _keyAccessor.GetKey(entity);
if (id == null)
throw new InvalidOperationException($"object id is missing");
await Collection.ReplaceOneAsync(GetBsonDocument(id), entity, new UpdateOptions() {IsUpsert = true});
@@ -52,19 +52,5 @@ private BsonDocument GetBsonDocument(TKey key)
var bsonValue = BsonValue.Create(key);
return new BsonDocument("_id", bsonValue);
}
-
- //public virtual Task BatchAddOrUpdate(TEntity[] entities)
- //{
- // var model = entities.Select(_ =>
- // {
- // if (!_.Id.HasValue)
- // _.Id = Guid.NewGuid();
- // return new ReplaceOneModel(new BsonDocument("_id", _.Id), _) { IsUpsert = true };
- // });
-
- // return Collection.BulkWriteAsync(model);
- //}
-
- //public virtual Task BatchDelete(Expression> predicate) => Collection.DeleteManyAsync(predicate);
}
}
\ No newline at end of file
diff --git a/src/Mocoding.AspNetCore.ODataApi.MongoDb/Extensions.cs b/src/Mocoding.AspNetCore.ODataApi.MongoDb/Extensions.cs
index 7277be2..b1f81a4 100644
--- a/src/Mocoding.AspNetCore.ODataApi.MongoDb/Extensions.cs
+++ b/src/Mocoding.AspNetCore.ODataApi.MongoDb/Extensions.cs
@@ -1,21 +1,23 @@
-using Microsoft.Extensions.DependencyInjection.Extensions;
+using System;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.DependencyInjection.Extensions;
using MongoDB.Driver;
namespace Mocoding.AspNetCore.ODataApi.MongoDb
{
public static class Extensions
{
- public static IODataApiBuilder AddODataApiMongoDb(this IODataApiBuilder oDataApiBuilder, string connection)
+ public static IServiceCollection AddMongoDbGenericRepository(this IServiceCollection services, string connection)
{
MongoDefaults.GuidRepresentation = MongoDB.Bson.GuidRepresentation.Standard;
- oDataApiBuilder.Services.TryAddSingleton(services =>
- {
- var urlBuilder = new MongoUrlBuilder(connection);
- var client = new MongoClient(connection);
- return client.GetDatabase(urlBuilder.DatabaseName);
- });
-
- return oDataApiBuilder;
+ services.TryAddSingleton(_ =>
+ {
+ var urlBuilder = new MongoUrlBuilder(connection);
+ var client = new MongoClient(connection);
+ return client.GetDatabase(urlBuilder.DatabaseName);
+ });
+ services.TryAddScoped(typeof(ICrudRepository<,>), typeof(CrudRepository<,>));
+ return services;
}
}
}
diff --git a/src/Mocoding.AspNetCore.ODataApi.MongoDb/IndexesExtensions.cs b/src/Mocoding.AspNetCore.ODataApi.MongoDb/IndexesExtensions.cs
index 7550ed6..3e001a7 100644
--- a/src/Mocoding.AspNetCore.ODataApi.MongoDb/IndexesExtensions.cs
+++ b/src/Mocoding.AspNetCore.ODataApi.MongoDb/IndexesExtensions.cs
@@ -1,11 +1,5 @@
using System;
-using System.Collections.Generic;
-using System.Globalization;
using System.Linq;
-using System.Reflection;
-using System.Text;
-using System.Threading.Tasks;
-using Microsoft.AspNetCore.Mvc.Internal;
using MongoDB.Driver;
namespace Mocoding.AspNetCore.ODataApi.MongoDb
diff --git a/src/Mocoding.AspNetCore.ODataApi.MongoDb/Mocoding.AspNetCore.ODataApi.MongoDb.csproj b/src/Mocoding.AspNetCore.ODataApi.MongoDb/Mocoding.AspNetCore.ODataApi.MongoDb.csproj
index 0522b69..9d6a644 100644
--- a/src/Mocoding.AspNetCore.ODataApi.MongoDb/Mocoding.AspNetCore.ODataApi.MongoDb.csproj
+++ b/src/Mocoding.AspNetCore.ODataApi.MongoDb/Mocoding.AspNetCore.ODataApi.MongoDb.csproj
@@ -1,23 +1,13 @@
-
+
+
- MongoDb storage provider for generic OData API implementation
- netstandard2.0
- netstandard;.net core;odata;generic;mongodb;storage;nosql
- Initial Release.
- https://mocoding.blob.core.windows.net/resources/odata-api/nugetIcon.png
- https://github.com/mocoding-software/odata-api
- https://raw.githubusercontent.com/mocoding-software/odata-api/master/LICENSE
- git
- https://github.com/mocoding-software/odata-api
- ..\..\_stylecop\StyleCop.ruleset
- Mocoding
+ MongoDb storage provider for generic OData API implementation
+ netstandard;.net core;odata;generic;mongodb;storage;nosql
+
-
-
-
+
-
diff --git a/src/Mocoding.AspNetCore.ODataApi/Core/CrudControllerFeatureProvider.cs b/src/Mocoding.AspNetCore.ODataApi/Core/CrudControllerFeatureProvider.cs
index afa1679..01786eb 100644
--- a/src/Mocoding.AspNetCore.ODataApi/Core/CrudControllerFeatureProvider.cs
+++ b/src/Mocoding.AspNetCore.ODataApi/Core/CrudControllerFeatureProvider.cs
@@ -1,9 +1,12 @@
using System;
using System.Collections.Generic;
+using System.Globalization;
using System.Linq;
using System.Reflection;
+using Microsoft.AspNet.OData;
using Microsoft.AspNetCore.Mvc.ApplicationParts;
using Microsoft.AspNetCore.Mvc.Controllers;
+using Microsoft.OData.Edm;
namespace Mocoding.AspNetCore.ODataApi.Core
{
@@ -22,13 +25,14 @@ public CrudControllerFeatureProvider(IModelMetadataProvider metadataProvider)
public void PopulateFeature(IEnumerable parts, ControllerFeature feature)
{
- var model = _metadataProvider.GetModelMetadata();
+ var model = _metadataProvider.GetEdmModel();
+ var entities = model.GetEntityKeyMapping();
// There's no 'real' controller for this entity, so add the generic version.
- foreach (var entityType in model)
+ foreach (var entity in entities)
{
var controllerType = typeof(CrudController<,>)
- .MakeGenericType(entityType.EntityType, entityType.EntityKey.PropertyType).GetTypeInfo();
+ .MakeGenericType(entity.Key, entity.Value.PropertyType).GetTypeInfo();
feature.Controllers.Add(controllerType);
}
}
diff --git a/src/Mocoding.AspNetCore.ODataApi/Core/CrudControllerNameConvention.cs b/src/Mocoding.AspNetCore.ODataApi/Core/CrudControllerNameConvention.cs
index 15b408b..c28948a 100644
--- a/src/Mocoding.AspNetCore.ODataApi/Core/CrudControllerNameConvention.cs
+++ b/src/Mocoding.AspNetCore.ODataApi/Core/CrudControllerNameConvention.cs
@@ -1,5 +1,6 @@
using System.Linq;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
+using Microsoft.OData.Edm;
namespace Mocoding.AspNetCore.ODataApi.Core
{
@@ -26,10 +27,10 @@ public void Apply(ControllerModel controller)
return;
var entityType = controllerType.GenericTypeArguments[0];
- var metadata = _metadataProvider.GetModelMetadata();
- var entityMetadata = metadata.FirstOrDefault(_ => _.EntityType == entityType);
- if (entityMetadata != null)
- controller.ControllerName = entityMetadata.Route;
+ var model = _metadataProvider.GetEdmModel();
+ var entitySet = model.EntityContainer.EntitySets().FirstOrDefault(_ => _.Type.AsElementType().FullTypeName() == entityType.FullName);
+ if (entitySet != null)
+ controller.ControllerName = entitySet.Name;
}
}
}
diff --git a/src/Mocoding.AspNetCore.ODataApi/Core/DefaultEntityKeyAccessor.cs b/src/Mocoding.AspNetCore.ODataApi/Core/DefaultEntityKeyAccessor.cs
index 7788313..645eeb2 100644
--- a/src/Mocoding.AspNetCore.ODataApi/Core/DefaultEntityKeyAccessor.cs
+++ b/src/Mocoding.AspNetCore.ODataApi/Core/DefaultEntityKeyAccessor.cs
@@ -1,24 +1,25 @@
using System;
using System.Collections.Generic;
using System.Linq;
-using System.Text;
+using System.Reflection;
+using Mocoding.AspNetCore.ODataApi.Core;
-namespace Mocoding.AspNetCore.ODataApi.Core
+namespace Mocoding.AspNetCore.ODataApi.DataAccess
{
- internal class DefaultEntityKeyAccessor : IEntityKeyAccossor
+ internal class DefaultEntityKeyAccessor : IEntityKeyAccessor
{
- private readonly IEnumerable _metadata;
+ private readonly IDictionary _mapping;
public DefaultEntityKeyAccessor(IModelMetadataProvider metadataProvider)
{
- _metadata = metadataProvider.GetModelMetadata();
+ _mapping = metadataProvider.GetEdmModel().GetEntityKeyMapping().ToDictionary(_ => _.Key, _ => _.Value);
}
public TKey GetKey(TEntity entity)
{
var entityType = typeof(TEntity);
- var entityMetadata = _metadata.First(_ => _.EntityType == entityType);
- return (TKey)entityMetadata.EntityKey.GetValue(entity);
+ var keyProperty = _mapping[entityType];
+ return (TKey)keyProperty.GetValue(entity);
}
}
}
diff --git a/src/Mocoding.AspNetCore.ODataApi/Core/EntityMetadata.cs b/src/Mocoding.AspNetCore.ODataApi/Core/EntityMetadata.cs
deleted file mode 100644
index d804267..0000000
--- a/src/Mocoding.AspNetCore.ODataApi/Core/EntityMetadata.cs
+++ /dev/null
@@ -1,29 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.Linq;
-using System.Reflection;
-using System.Text;
-using Microsoft.OData.Edm;
-
-namespace Mocoding.AspNetCore.ODataApi.Core
-{
- internal class EntityMetadata
- {
- public EntityMetadata(Type entityType, string route)
- {
- EntityType = entityType;
- Route = route;
- }
-
- public Type EntityType { get; }
- public PropertyInfo EntityKey { get; private set; }
- public string Route { get; }
-
- public void SetKey(IEdmEntityType edmType)
- {
- var key = edmType.DeclaredKey.First();
- EntityKey = EntityType.GetProperty(key.Name) ?? EntityType.GetProperty(CultureInfo.CurrentCulture.TextInfo.ToTitleCase(key.Name));
- }
- }
-}
diff --git a/src/Mocoding.AspNetCore.ODataApi/Core/IModelMetadataProvider.cs b/src/Mocoding.AspNetCore.ODataApi/Core/IModelMetadataProvider.cs
index e38d8dc..e9e9b77 100644
--- a/src/Mocoding.AspNetCore.ODataApi/Core/IModelMetadataProvider.cs
+++ b/src/Mocoding.AspNetCore.ODataApi/Core/IModelMetadataProvider.cs
@@ -1,7 +1,6 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
+using System.Collections.Generic;
using Microsoft.OData.Edm;
+using Mocoding.AspNetCore.ODataApi.DataAccess;
namespace Mocoding.AspNetCore.ODataApi.Core
{
@@ -9,6 +8,6 @@ internal interface IModelMetadataProvider
{
IEdmModel GetEdmModel();
- IEnumerable GetModelMetadata();
+ // IEnumerable GetModelMetadata();
}
}
diff --git a/src/Mocoding.AspNetCore.ODataApi/Core/ODataApiBuilder.cs b/src/Mocoding.AspNetCore.ODataApi/Core/ODataApiBuilder.cs
index dad1505..a4c1cc9 100644
--- a/src/Mocoding.AspNetCore.ODataApi/Core/ODataApiBuilder.cs
+++ b/src/Mocoding.AspNetCore.ODataApi/Core/ODataApiBuilder.cs
@@ -4,34 +4,25 @@
using Microsoft.AspNet.OData.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.OData.Edm;
+using Mocoding.AspNetCore.ODataApi.DataAccess;
namespace Mocoding.AspNetCore.ODataApi.Core
{
internal class ODataApiBuilder : IODataApiBuilder, IModelMetadataProvider
{
private readonly ODataConventionModelBuilder _modelBuilder;
- private readonly IList _metadata;
private IEdmModel _model;
- public ODataApiBuilder(IServiceCollection services, bool enableLowerCamelCase)
+ public ODataApiBuilder(bool enableLowerCamelCase)
{
- Services = services;
_modelBuilder = new ODataConventionModelBuilder();
if (enableLowerCamelCase)
_modelBuilder.EnableLowerCamelCase();
- _metadata = new List();
}
- public IServiceCollection Services { get; }
-
public IEdmModel GetEdmModel()
{
- return _model ?? (_model = GetEdmModelInternal());
- }
-
- public IEnumerable GetModelMetadata()
- {
- return _metadata;
+ return _model ??= _modelBuilder.GetEdmModel();
}
public IODataApiBuilder AddResource(string customRoute = null)
@@ -44,23 +35,9 @@ public IODataApiBuilder AddResource(string customRoute = null)
public IODataApiBuilder AddResource(Type type, string customRoute = null)
{
var route = customRoute ?? type.Name.ToLower();
- _metadata.Add(new EntityMetadata(type, route));
var entityType = _modelBuilder.AddEntityType(type);
_modelBuilder.AddEntitySet(route, entityType);
return this;
}
-
- private IEdmModel GetEdmModelInternal()
- {
- var model = _modelBuilder.GetEdmModel();
- var edmTypes = model.SchemaElements.Where(_ => _ is IEdmEntityType).Cast();
- foreach (var edmType in edmTypes)
- {
- var metadataType = _metadata.First(_ => _.EntityType.FullName == edmType.FullTypeName());
- metadataType?.SetKey(edmType);
- }
-
- return model;
- }
}
}
\ No newline at end of file
diff --git a/src/Mocoding.AspNetCore.ODataApi/CrudController.cs b/src/Mocoding.AspNetCore.ODataApi/CrudController.cs
index 4959c9f..2594567 100644
--- a/src/Mocoding.AspNetCore.ODataApi/CrudController.cs
+++ b/src/Mocoding.AspNetCore.ODataApi/CrudController.cs
@@ -1,5 +1,4 @@
-using System;
-using System.Collections.Generic;
+using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNet.OData;
@@ -36,7 +35,7 @@ public virtual async Task Get([FromODataUri] TKey key)
public virtual async Task> Post([FromBody]TEntity entity)
{
await Repository.AddOrUpdate(entity);
- return base.Created(entity);
+ return Created(entity);
}
public virtual async Task> Put(TKey key, [FromBody]Delta patch)
@@ -46,7 +45,7 @@ public virtual async Task> Put(TKey key, [FromBody]D
throw new KeyNotFoundException();
patch.Put(entity);
await Repository.AddOrUpdate(entity);
- return base.Updated(entity);
+ return Updated(entity);
}
public virtual async Task> Patch(TKey key, [FromBody]Delta patch)
@@ -57,7 +56,7 @@ public virtual async Task> Patch(TKey key, [FromBody
patch.Patch(entity);
await Repository.AddOrUpdate(entity);
- return base.Updated(entity);
+ return Updated(entity);
}
public virtual async Task Delete(TKey key)
diff --git a/src/Mocoding.AspNetCore.ODataApi/EdmExtensions.cs b/src/Mocoding.AspNetCore.ODataApi/EdmExtensions.cs
new file mode 100644
index 0000000..95cb398
--- /dev/null
+++ b/src/Mocoding.AspNetCore.ODataApi/EdmExtensions.cs
@@ -0,0 +1,30 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using Microsoft.AspNet.OData;
+using Microsoft.OData.Edm;
+
+namespace Mocoding.AspNetCore.ODataApi
+{
+ public static class EdmExtensions
+ {
+ public static IEnumerable> GetEntityKeyMapping(this IEdmModel model)
+ {
+ var entities = model.SchemaElements.Where(_ => _ is IEdmEntityType).Cast();
+
+ // There's no 'real' controller for this entity, so add the generic version.
+ foreach (var entity in entities)
+ {
+ var key = entity.DeclaredKey.First();
+ var annotation = model.GetAnnotationValue(entity);
+ var entityType = annotation.ClrType;
+ var keyProperty = entityType?.GetProperty(key.Name) ?? entityType?.GetProperty(CultureInfo.CurrentCulture.TextInfo.ToTitleCase(key.Name));
+
+ yield return new KeyValuePair(entityType, keyProperty);
+ }
+ }
+ }
+}
diff --git a/src/Mocoding.AspNetCore.ODataApi/ICrudRepository.cs b/src/Mocoding.AspNetCore.ODataApi/ICrudRepository.cs
index cb44eb6..3b3abb2 100644
--- a/src/Mocoding.AspNetCore.ODataApi/ICrudRepository.cs
+++ b/src/Mocoding.AspNetCore.ODataApi/ICrudRepository.cs
@@ -1,6 +1,4 @@
-using System;
-using System.Linq;
-using System.Linq.Expressions;
+using System.Linq;
using System.Threading.Tasks;
namespace Mocoding.AspNetCore.ODataApi
@@ -12,8 +10,5 @@ public interface ICrudRepository
Task AddOrUpdate(T entity);
Task FindByKey(TKey key);
Task DeleteByKey(TKey key);
-
- // Task BatchAddOrUpdate(T[] entities);
- // Task BatchDelete(Expression> predicate);
}
}
diff --git a/src/Mocoding.AspNetCore.ODataApi/IEntityKeyAccessor.cs b/src/Mocoding.AspNetCore.ODataApi/IEntityKeyAccessor.cs
new file mode 100644
index 0000000..773dea4
--- /dev/null
+++ b/src/Mocoding.AspNetCore.ODataApi/IEntityKeyAccessor.cs
@@ -0,0 +1,7 @@
+namespace Mocoding.AspNetCore.ODataApi
+{
+ public interface IEntityKeyAccessor
+ {
+ TKey GetKey(TEntity entity);
+ }
+}
diff --git a/src/Mocoding.AspNetCore.ODataApi/IEntityKeyAccossor.cs b/src/Mocoding.AspNetCore.ODataApi/IEntityKeyAccossor.cs
deleted file mode 100644
index 45b63d3..0000000
--- a/src/Mocoding.AspNetCore.ODataApi/IEntityKeyAccossor.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-
-namespace Mocoding.AspNetCore.ODataApi
-{
- public interface IEntityKeyAccossor
- {
- TKey GetKey(TEntity entity);
- }
-}
diff --git a/src/Mocoding.AspNetCore.ODataApi/IODataApiBuilder.cs b/src/Mocoding.AspNetCore.ODataApi/IODataApiBuilder.cs
index 9b4ffe9..6e39ebb 100644
--- a/src/Mocoding.AspNetCore.ODataApi/IODataApiBuilder.cs
+++ b/src/Mocoding.AspNetCore.ODataApi/IODataApiBuilder.cs
@@ -1,15 +1,10 @@
using System;
-using System.Collections.Generic;
using Microsoft.Extensions.DependencyInjection;
-using Microsoft.OData.Edm;
-using Mocoding.AspNetCore.ODataApi.Core;
namespace Mocoding.AspNetCore.ODataApi
{
public interface IODataApiBuilder
{
- IServiceCollection Services { get; }
-
IODataApiBuilder AddResource(string customRoute = null)
where T : class;
IODataApiBuilder AddResource(Type type, string customRoute = null);
diff --git a/src/Mocoding.AspNetCore.ODataApi/Mocoding.AspNetCore.ODataApi.csproj b/src/Mocoding.AspNetCore.ODataApi/Mocoding.AspNetCore.ODataApi.csproj
index 6a43632..dd8a7f1 100644
--- a/src/Mocoding.AspNetCore.ODataApi/Mocoding.AspNetCore.ODataApi.csproj
+++ b/src/Mocoding.AspNetCore.ODataApi/Mocoding.AspNetCore.ODataApi.csproj
@@ -1,25 +1,13 @@
-
+
+
Generic OData API v4+ implementation for .NET Standard.
- netstandard2.0
- netstandard;.net core;odata;generic;api
- Initial Reelase.
- https://mocoding.blob.core.windows.net/resources/odata-api/nugetIcon.png
- https://github.com/mocoding-software/odata-api
- https://raw.githubusercontent.com/mocoding-software/odata-api/master/LICENSE
- git
- https://github.com/mocoding-software/odata-api
- ..\..\_stylecop\StyleCop.ruleset
- Mocoding
-
+ netstandard;.net core;odata;generic;api
+
-
-
- all
- 1.0.2
-
+
diff --git a/src/Mocoding.AspNetCore.ODataApi/ODataApiExtensions.cs b/src/Mocoding.AspNetCore.ODataApi/ODataApiExtensions.cs
index 1daf944..1349f8b 100644
--- a/src/Mocoding.AspNetCore.ODataApi/ODataApiExtensions.cs
+++ b/src/Mocoding.AspNetCore.ODataApi/ODataApiExtensions.cs
@@ -1,44 +1,66 @@
-using System.Linq;
+using System;
using Microsoft.AspNet.OData.Extensions;
-using Microsoft.AspNet.OData.Formatter;
-using Microsoft.AspNet.OData.Query;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
-using Microsoft.Net.Http.Headers;
using Mocoding.AspNetCore.ODataApi.Core;
+using Mocoding.AspNetCore.ODataApi.DataAccess;
namespace Mocoding.AspNetCore.ODataApi
{
public static class ODataApiExtensions
{
+ ///
+ /// Adds required services to support OData API.
+ ///
+ /// The MVC.
+ /// if set to true [enable lower camel case].
+ /// Builder to manipulate resources.
public static IODataApiBuilder AddODataApi(this IMvcCoreBuilder mvc, bool enableLowerCamelCase = true)
{
var services = mvc.Services;
- var modelBuilder = new ODataApiBuilder(services, enableLowerCamelCase);
+ var modelBuilder = new ODataApiBuilder(enableLowerCamelCase);
services.AddOData();
services.AddSingleton(modelBuilder);
- services.TryAddSingleton();
+ services.TryAddSingleton();
mvc.AddMvcOptions(options => options.Conventions.Add(new CrudControllerNameConvention(modelBuilder)))
.ConfigureApplicationPartManager(p => p.FeatureProviders.Add(new CrudControllerFeatureProvider(modelBuilder)));
return modelBuilder;
}
- public static IRouteBuilder UseOData(this IRouteBuilder routeBuilder, IApplicationBuilder app, string routePrfix = ODataApiOptions.DefaultRoute)
+ ///
+ /// Adds OData API middleware to the pipeline.
+ ///
+ /// The to add the middleware to.
+ /// The route prefix.
+ /// A reference to this instance after the operation has completed.
+ public static IApplicationBuilder UseODataApi(this IApplicationBuilder app, string routePrefix = ODataApiOptions.DefaultRoute)
{
- return routeBuilder.UseOData(app, new ODataApiOptions() { RoutePrfix = routePrfix });
+ return app.UseODataApi(new ODataApiOptions() { RoutePrefix = routePrefix }, null);
}
- public static IRouteBuilder UseOData(this IRouteBuilder routeBuilder, IApplicationBuilder app, ODataApiOptions options)
+ ///
+ /// Adds OData API middleware to the pipeline with additional customization options
+ ///
+ /// The to add the middleware to.
+ /// The options.
+ /// An to configure the provided .
+ /// A reference to this instance after the operation has completed.
+ public static IApplicationBuilder UseODataApi(this IApplicationBuilder app, ODataApiOptions options, Action configure)
{
var apiBuilder = app.ApplicationServices.GetRequiredService();
- routeBuilder.Filter().Select().Expand().Count().OrderBy().MaxTop(null);
- routeBuilder.MapODataServiceRoute("OData", options.RoutePrfix, apiBuilder.GetEdmModel());
-
- return routeBuilder;
+ return app
+ .UseRouting()
+ .UseEndpoints(endpoints =>
+ {
+ endpoints.Filter().Select().Expand().Count().OrderBy().MaxTop(null);
+ endpoints.MapODataRoute("OData", options.RoutePrefix, apiBuilder.GetEdmModel());
+ endpoints.MapControllers();
+ configure?.Invoke(endpoints);
+ });
}
}
}
\ No newline at end of file
diff --git a/src/Mocoding.AspNetCore.ODataApi/ODataApiOptions.cs b/src/Mocoding.AspNetCore.ODataApi/ODataApiOptions.cs
index 741b33a..05978e0 100644
--- a/src/Mocoding.AspNetCore.ODataApi/ODataApiOptions.cs
+++ b/src/Mocoding.AspNetCore.ODataApi/ODataApiOptions.cs
@@ -1,19 +1,23 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-using Microsoft.AspNet.OData.Builder;
-
-namespace Mocoding.AspNetCore.ODataApi
+namespace Mocoding.AspNetCore.ODataApi
{
+ ///
+ /// ODataApi Options
+ ///
public class ODataApiOptions
{
public const string DefaultRoute = "odata";
public ODataApiOptions()
{
- RoutePrfix = DefaultRoute;
+ RoutePrefix = DefaultRoute;
}
- public string RoutePrfix { get; set; }
+ ///
+ /// Gets or sets the route prefix.
+ ///
+ ///
+ /// The route prefix.
+ ///
+ public string RoutePrefix { get; set; }
}
}
diff --git a/src/ProjectBuildProperties.targets b/src/ProjectBuildProperties.targets
new file mode 100644
index 0000000..0f23a45
--- /dev/null
+++ b/src/ProjectBuildProperties.targets
@@ -0,0 +1,31 @@
+
+
+ netcoreapp3.1
+
+ https://mocoding.blob.core.windows.net/resources/odata-api/nugetIcon.png
+ https://github.com/mocoding-software/odata-api
+ https://raw.githubusercontent.com/mocoding-software/odata-api/master/LICENSE
+ git
+ https://github.com/mocoding-software/odata-api
+ ..\..\StyleCop.ruleset
+ MOCODING LLC,Dennis Miasoutov
+ Full
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
diff --git a/test/Mocoding.AspNetCore.ODataApi.Tests/CrudControllerTests.cs b/test/Mocoding.AspNetCore.ODataApi.Tests/CrudControllerTests.cs
new file mode 100644
index 0000000..8a9c631
--- /dev/null
+++ b/test/Mocoding.AspNetCore.ODataApi.Tests/CrudControllerTests.cs
@@ -0,0 +1,134 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Microsoft.AspNet.OData;
+using Microsoft.AspNetCore.Mvc;
+using NSubstitute;
+using WebApp;
+using Xunit;
+
+namespace Mocoding.AspNetCore.ODataApi.Tests
+{
+ public class CrudControllerTests
+ {
+ [Fact]
+ public void GetTest()
+ {
+ var repo = Substitute.For>();
+ var controller = new CrudController(repo);
+
+ controller.Get();
+
+ repo.Received().QueryRecords();
+ }
+
+ [Fact]
+ public async void GetByIdTest()
+ {
+ var repo = Substitute.For>();
+ var controller = new CrudController(repo);
+
+ var user = new User() { Name = "Test"};
+ repo.FindByKey(Arg.Is(Guid.Empty)).Returns(user);
+
+ var result = await controller.Get(Guid.Empty) as OkObjectResult;
+
+ Assert.Same(user, result?.Value);
+ }
+
+ [Fact]
+ public async void GetByIdNotFoundTest()
+ {
+ var repo = Substitute.For>();
+ var controller = new CrudController(repo);
+
+ User user = null;
+ // ReSharper disable once ExpressionIsAlwaysNull
+ repo.FindByKey(Arg.Is(Guid.Empty)).Returns(user);
+
+ var result = await controller.Get(Guid.Empty) as NotFoundResult;
+
+ Assert.NotNull(result);
+ }
+
+ [Fact]
+ public async void PostTest()
+ {
+ var repo = Substitute.For>();
+ var controller = new CrudController(repo);
+
+ var user = new User();
+
+ var result = await controller.Post(user);
+
+ Assert.NotNull(result);
+ await repo.Received().AddOrUpdate(Arg.Is(user));
+ }
+
+ [Fact]
+ public async void PutTest()
+ {
+ var repo = Substitute.For>();
+ var controller = new CrudController(repo);
+
+ var user = new User();
+ repo.FindByKey(Arg.Is(Guid.Empty)).Returns(user);
+ var result = await controller.Put(Guid.Empty, new Delta(typeof(User)));
+
+ Assert.NotNull(result);
+ await repo.Received().AddOrUpdate(Arg.Is(user));
+ }
+
+ [Fact]
+ public async void PutNotFoundTest()
+ {
+ var repo = Substitute.For>();
+ var controller = new CrudController(repo);
+
+ User user = null;
+ // ReSharper disable once ExpressionIsAlwaysNull
+ repo.FindByKey(Arg.Is(Guid.Empty)).Returns(user);
+ await Assert.ThrowsAsync(async () =>
+ await controller.Put(Guid.Empty, new Delta(typeof(User))));
+ }
+
+ [Fact]
+ public async void PatchTest()
+ {
+ var repo = Substitute.For>();
+ var controller = new CrudController(repo);
+
+ var user = new User();
+ repo.FindByKey(Arg.Is(Guid.Empty)).Returns(user);
+ var result = await controller.Patch(Guid.Empty, new Delta(typeof(User)));
+
+ Assert.NotNull(result);
+ await repo.Received().AddOrUpdate(Arg.Is(user));
+ }
+
+ [Fact]
+ public async void PatchNotFoundTest()
+ {
+ var repo = Substitute.For>();
+ var controller = new CrudController(repo);
+
+ User user = null;
+ // ReSharper disable once ExpressionIsAlwaysNull
+ repo.FindByKey(Arg.Is(Guid.Empty)).Returns(user);
+ await Assert.ThrowsAsync(async () =>
+ await controller.Patch(Guid.Empty, new Delta(typeof(User))));
+ }
+
+ [Fact]
+ public async void DeleteTest()
+ {
+ var repo = Substitute.For>();
+ var controller = new CrudController(repo);
+
+
+ await controller.Delete(Guid.Empty);
+
+ await repo.Received().DeleteByKey(Guid.Empty);
+ }
+ }
+}
diff --git a/test/Mocoding.AspNetCore.ODataApi.Tests/Factories/EasyDocDbWebAppFactory.cs b/test/Mocoding.AspNetCore.ODataApi.Tests/Factories/EasyDocDbWebAppFactory.cs
new file mode 100644
index 0000000..dd0e662
--- /dev/null
+++ b/test/Mocoding.AspNetCore.ODataApi.Tests/Factories/EasyDocDbWebAppFactory.cs
@@ -0,0 +1,19 @@
+using Microsoft.AspNetCore;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Mvc.Testing;
+
+namespace Mocoding.AspNetCore.ODataApi.Tests.Factories
+{
+ public class EasyDocDbWebAppFactory : WebApplicationFactory
+ {
+ protected override IWebHostBuilder CreateWebHostBuilder()
+ {
+ return WebHost.CreateDefaultBuilder();
+ }
+
+ protected override void ConfigureWebHost(IWebHostBuilder builder)
+ {
+ builder.UseStartup();
+ }
+ }
+}
diff --git a/test/Mocoding.AspNetCore.ODataApi.Tests/Factories/EntityFrameworkWebAppFactory.cs b/test/Mocoding.AspNetCore.ODataApi.Tests/Factories/EntityFrameworkWebAppFactory.cs
new file mode 100644
index 0000000..4839929
--- /dev/null
+++ b/test/Mocoding.AspNetCore.ODataApi.Tests/Factories/EntityFrameworkWebAppFactory.cs
@@ -0,0 +1,19 @@
+using Microsoft.AspNetCore;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Mvc.Testing;
+
+namespace Mocoding.AspNetCore.ODataApi.Tests.Factories
+{
+ public class EntityFrameworkWebAppFactory : WebApplicationFactory
+ {
+ protected override IWebHostBuilder CreateWebHostBuilder()
+ {
+ return WebHost.CreateDefaultBuilder();
+ }
+
+ protected override void ConfigureWebHost(IWebHostBuilder builder)
+ {
+ builder.UseStartup();
+ }
+ }
+}
diff --git a/test/Mocoding.AspNetCore.ODataApi.Tests/Factories/Factory.cs b/test/Mocoding.AspNetCore.ODataApi.Tests/Factories/Factory.cs
new file mode 100644
index 0000000..56be27e
--- /dev/null
+++ b/test/Mocoding.AspNetCore.ODataApi.Tests/Factories/Factory.cs
@@ -0,0 +1,20 @@
+using Microsoft.AspNetCore;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Mvc.Testing;
+
+namespace Mocoding.AspNetCore.ODataApi.Tests.Factories
+{
+ public class Factory : WebApplicationFactory
+ {
+ protected override IWebHostBuilder CreateWebHostBuilder()
+ {
+ return WebHost.CreateDefaultBuilder();
+ }
+
+ protected override void ConfigureWebHost(IWebHostBuilder builder)
+ {
+ builder.UseContentRoot(".");
+ builder.UseStartup();
+ }
+ }
+}
diff --git a/test/Mocoding.AspNetCore.ODataApi.Tests/Factories/Startup.cs b/test/Mocoding.AspNetCore.ODataApi.Tests/Factories/Startup.cs
new file mode 100644
index 0000000..d0d1fa5
--- /dev/null
+++ b/test/Mocoding.AspNetCore.ODataApi.Tests/Factories/Startup.cs
@@ -0,0 +1,22 @@
+using Microsoft.AspNetCore.Builder;
+using Microsoft.Extensions.DependencyInjection;
+using WebApp;
+
+namespace Mocoding.AspNetCore.ODataApi.Tests.Factories
+{
+ public class Startup
+ {
+ public void ConfigureServices(IServiceCollection services)
+ {
+ services
+ .AddMvcCore()
+ .AddODataApi()
+ .AddResource();
+ }
+
+ public void Configure(IApplicationBuilder app)
+ {
+ app.UseODataApi();
+ }
+ }
+}
diff --git a/test/Mocoding.AspNetCore.ODataApi.Tests/Integration/EasyDocDbExtensionsTests.cs b/test/Mocoding.AspNetCore.ODataApi.Tests/Integration/EasyDocDbExtensionsTests.cs
new file mode 100644
index 0000000..28de33a
--- /dev/null
+++ b/test/Mocoding.AspNetCore.ODataApi.Tests/Integration/EasyDocDbExtensionsTests.cs
@@ -0,0 +1,26 @@
+using System.Net.Http;
+using Microsoft.AspNetCore.Mvc.Testing;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.OData.Client;
+using Mocoding.AspNetCore.ODataApi.EasyDocDb;
+using Mocoding.AspNetCore.ODataApi.Tests.Factories;
+using Xunit;
+
+namespace Mocoding.AspNetCore.ODataApi.Tests.Integration
+{
+ public class EasyDocDbExtensionsTests : IClassFixture
+ {
+ private readonly EasyDocDbWebAppFactory _factory;
+
+ public EasyDocDbExtensionsTests(EasyDocDbWebAppFactory factory)
+ {
+ _factory = factory;
+ }
+
+ [Fact]
+ public void EasyDocDbServicesTest()
+ {
+ Assert.NotNull(_factory.Services.GetRequiredService());
+ }
+ }
+}
diff --git a/test/Mocoding.AspNetCore.ODataApi.Tests/Integration/ODataApiExtensionsTests.cs b/test/Mocoding.AspNetCore.ODataApi.Tests/Integration/ODataApiExtensionsTests.cs
new file mode 100644
index 0000000..b0f1663
--- /dev/null
+++ b/test/Mocoding.AspNetCore.ODataApi.Tests/Integration/ODataApiExtensionsTests.cs
@@ -0,0 +1,25 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Microsoft.Extensions.DependencyInjection;
+using Mocoding.AspNetCore.ODataApi.Tests.Factories;
+using Xunit;
+
+namespace Mocoding.AspNetCore.ODataApi.Tests.Integration
+{
+ public class ODataApiExtensionsTests : IClassFixture
+ {
+ private readonly Factory _factory;
+
+ public ODataApiExtensionsTests(Factory factory)
+ {
+ _factory = factory;
+ }
+
+ [Fact]
+ public void ServicesTest()
+ {
+ Assert.NotNull(_factory.Services.GetRequiredService());
+ }
+ }
+}
diff --git a/test/Mocoding.AspNetCore.ODataApi.Tests/Mocoding.AspNetCore.ODataApi.Tests.csproj b/test/Mocoding.AspNetCore.ODataApi.Tests/Mocoding.AspNetCore.ODataApi.Tests.csproj
new file mode 100644
index 0000000..47fc8c5
--- /dev/null
+++ b/test/Mocoding.AspNetCore.ODataApi.Tests/Mocoding.AspNetCore.ODataApi.Tests.csproj
@@ -0,0 +1,40 @@
+
+
+
+ MOCODING LLC, Dennis Miasoutov
+ netcoreapp3.1
+ ..\..\StyleCop.ruleset
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
+
+
+
+
+
+