diff --git a/OSLC4Net_SDK/.dockerignore b/OSLC4Net_SDK/.dockerignore new file mode 100644 index 0000000..fe1152b --- /dev/null +++ b/OSLC4Net_SDK/.dockerignore @@ -0,0 +1,30 @@ +**/.classpath +**/.dockerignore +**/.env +**/.git +**/.gitignore +**/.project +**/.settings +**/.toolstarget +**/.vs +**/.vscode +**/*.*proj.user +**/*.dbmdl +**/*.jfm +**/azds.yaml +**/bin +**/charts +**/docker-compose* +**/Dockerfile* +**/node_modules +**/npm-debug.log +**/obj +**/secrets.dev.yaml +**/values.dev.yaml +LICENSE +README.md +!**/.gitignore +!.git/HEAD +!.git/config +!.git/packed-refs +!.git/refs/heads/** \ No newline at end of file diff --git a/OSLC4Net_SDK/Directory.Packages.props b/OSLC4Net_SDK/Directory.Packages.props index b8c6224..82ef828 100644 --- a/OSLC4Net_SDK/Directory.Packages.props +++ b/OSLC4Net_SDK/Directory.Packages.props @@ -10,10 +10,10 @@ + - @@ -40,5 +40,6 @@ + diff --git a/OSLC4Net_SDK/Examples/OSLC4NetExamples.Server.NetCoreApi/Controllers/WeatherForecastController.cs b/OSLC4Net_SDK/Examples/OSLC4NetExamples.Server.NetCoreApi/Controllers/WeatherForecastController.cs new file mode 100644 index 0000000..c02fa7a --- /dev/null +++ b/OSLC4Net_SDK/Examples/OSLC4NetExamples.Server.NetCoreApi/Controllers/WeatherForecastController.cs @@ -0,0 +1,43 @@ +using Microsoft.AspNetCore.Http.Extensions; +using Microsoft.AspNetCore.Mvc; + +namespace OSLC4NetExamples.Server.NetCoreApi.Controllers; +[ApiController] +[Route("[controller]")] +public class WeatherForecastController : ControllerBase +{ + private static readonly string[] Summaries = new[] + { + "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" + }; + + private readonly ILogger _logger; + + public WeatherForecastController(ILogger logger) + { + _logger = logger; + } + + [HttpGet] + [Route("oslc")] + public OSLC4Net.Core.Model.ServiceProvider Oslc() + { + var sp = new OSLC4Net.Core.Model.ServiceProvider(); + sp.SetAbout(new Uri(Request.GetEncodedUrl())); + sp.SetDescription("test me"); + return sp; + } + + [HttpGet(Name = "GetWeatherForecast")] + [Route("forecast")] + public IEnumerable Get() + { + return Enumerable.Range(1, 5).Select(index => new WeatherForecast + { + Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)), + TemperatureC = Random.Shared.Next(-20, 55), + Summary = Summaries[Random.Shared.Next(Summaries.Length)] + }) + .ToArray(); + } +} diff --git a/OSLC4Net_SDK/Examples/OSLC4NetExamples.Server.NetCoreApi/Dockerfile b/OSLC4Net_SDK/Examples/OSLC4NetExamples.Server.NetCoreApi/Dockerfile new file mode 100644 index 0000000..59b7da4 --- /dev/null +++ b/OSLC4Net_SDK/Examples/OSLC4NetExamples.Server.NetCoreApi/Dockerfile @@ -0,0 +1,31 @@ +# See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging. + +# This stage is used when running from VS in fast mode (Default for Debug configuration) +FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base +USER app +WORKDIR /app +EXPOSE 8080 +EXPOSE 8081 + + +# This stage is used to build the service project +FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build +ARG BUILD_CONFIGURATION=Release +WORKDIR /src +COPY ["Examples/Directory.Build.props", "Examples/"] +COPY ["Examples/OSLC4NetExamples.Server.NetCoreApi/OSLC4NetExamples.Server.NetCoreApi.csproj", "Examples/OSLC4NetExamples.Server.NetCoreApi/"] +RUN dotnet restore "./Examples/OSLC4NetExamples.Server.NetCoreApi/OSLC4NetExamples.Server.NetCoreApi.csproj" +COPY . . +WORKDIR "/src/Examples/OSLC4NetExamples.Server.NetCoreApi" +RUN dotnet build "./OSLC4NetExamples.Server.NetCoreApi.csproj" -c $BUILD_CONFIGURATION -o /app/build + +# This stage is used to publish the service project to be copied to the final stage +FROM build AS publish +ARG BUILD_CONFIGURATION=Release +RUN dotnet publish "./OSLC4NetExamples.Server.NetCoreApi.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false + +# This stage is used in production or when running from VS in regular mode (Default when not using the Debug configuration) +FROM base AS final +WORKDIR /app +COPY --from=publish /app/publish . +ENTRYPOINT ["dotnet", "OSLC4NetExamples.Server.NetCoreApi.dll"] \ No newline at end of file diff --git a/OSLC4Net_SDK/Examples/OSLC4NetExamples.Server.NetCoreApi/OSLC4NetExamples.Server.NetCoreApi.csproj b/OSLC4Net_SDK/Examples/OSLC4NetExamples.Server.NetCoreApi/OSLC4NetExamples.Server.NetCoreApi.csproj new file mode 100644 index 0000000..8ed5bab --- /dev/null +++ b/OSLC4Net_SDK/Examples/OSLC4NetExamples.Server.NetCoreApi/OSLC4NetExamples.Server.NetCoreApi.csproj @@ -0,0 +1,21 @@ + + + + net8.0 + enable + enable + 9d68bd64-651d-4baa-9904-6369c55b51cc + Linux + ..\.. + + + + + + + + + + + + diff --git a/OSLC4Net_SDK/Examples/OSLC4NetExamples.Server.NetCoreApi/OSLC4NetExamples.Server.NetCoreApi.http b/OSLC4Net_SDK/Examples/OSLC4NetExamples.Server.NetCoreApi/OSLC4NetExamples.Server.NetCoreApi.http new file mode 100644 index 0000000..e367faa --- /dev/null +++ b/OSLC4Net_SDK/Examples/OSLC4NetExamples.Server.NetCoreApi/OSLC4NetExamples.Server.NetCoreApi.http @@ -0,0 +1,6 @@ +@OSLC4NetExamples.Server.NetCoreApi_HostAddress = http://localhost:5065 + +GET {{OSLC4NetExamples.Server.NetCoreApi_HostAddress}}/weatherforecast/ +Accept: application/json + +### diff --git a/OSLC4Net_SDK/Examples/OSLC4NetExamples.Server.NetCoreApi/Program.cs b/OSLC4Net_SDK/Examples/OSLC4NetExamples.Server.NetCoreApi/Program.cs new file mode 100644 index 0000000..c4b7a73 --- /dev/null +++ b/OSLC4Net_SDK/Examples/OSLC4NetExamples.Server.NetCoreApi/Program.cs @@ -0,0 +1,31 @@ +using OSLC4Net.Server.Providers; + +var builder = WebApplication.CreateBuilder(args); + +// Add services to the container. + +builder.Services.AddControllers(options => +{ + options.InputFormatters.Insert(0, new OslcRdfInputFormatter()); + options.OutputFormatters.Insert(0, new OslcRdfOutputFormatter()); +}); +// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle +builder.Services.AddEndpointsApiExplorer(); +builder.Services.AddSwaggerGen(); + +var app = builder.Build(); + +// Configure the HTTP request pipeline. +if (app.Environment.IsDevelopment()) +{ + // app.UseSwagger(); + // app.UseSwaggerUI(); +} + +app.UseHttpsRedirection(); + +app.UseAuthorization(); + +app.MapControllers(); + +app.Run(); diff --git a/OSLC4Net_SDK/Examples/OSLC4NetExamples.Server.NetCoreApi/Properties/launchSettings.json b/OSLC4Net_SDK/Examples/OSLC4NetExamples.Server.NetCoreApi/Properties/launchSettings.json new file mode 100644 index 0000000..85d9de6 --- /dev/null +++ b/OSLC4Net_SDK/Examples/OSLC4NetExamples.Server.NetCoreApi/Properties/launchSettings.json @@ -0,0 +1,52 @@ +{ + "profiles": { + "http": { + "commandName": "Project", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "dotnetRunMessages": true, + "applicationUrl": "http://localhost:5065" + }, + "https": { + "commandName": "Project", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "dotnetRunMessages": true, + "applicationUrl": "https://localhost:7270;http://localhost:5065" + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "Container (Dockerfile)": { + "commandName": "Docker", + "launchBrowser": true, + "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/swagger", + "environmentVariables": { + "ASPNETCORE_HTTPS_PORTS": "8081", + "ASPNETCORE_HTTP_PORTS": "8080" + }, + "publishAllPorts": true, + "useSSL": true + } + }, + "$schema": "http://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:23478", + "sslPort": 44387 + } + } +} \ No newline at end of file diff --git a/OSLC4Net_SDK/Examples/OSLC4NetExamples.Server.NetCoreApi/WeatherForecast.cs b/OSLC4Net_SDK/Examples/OSLC4NetExamples.Server.NetCoreApi/WeatherForecast.cs new file mode 100644 index 0000000..0733191 --- /dev/null +++ b/OSLC4Net_SDK/Examples/OSLC4NetExamples.Server.NetCoreApi/WeatherForecast.cs @@ -0,0 +1,12 @@ +namespace OSLC4NetExamples.Server.NetCoreApi; + +public class WeatherForecast +{ + public DateOnly Date { get; set; } + + public int TemperatureC { get; set; } + + public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); + + public string? Summary { get; set; } +} diff --git a/OSLC4Net_SDK/Examples/OSLC4NetExamples.Server.NetCoreApi/appsettings.Development.json b/OSLC4Net_SDK/Examples/OSLC4NetExamples.Server.NetCoreApi/appsettings.Development.json new file mode 100644 index 0000000..0c208ae --- /dev/null +++ b/OSLC4Net_SDK/Examples/OSLC4NetExamples.Server.NetCoreApi/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/OSLC4Net_SDK/Examples/OSLC4NetExamples.Server.NetCoreApi/appsettings.json b/OSLC4Net_SDK/Examples/OSLC4NetExamples.Server.NetCoreApi/appsettings.json new file mode 100644 index 0000000..10f68b8 --- /dev/null +++ b/OSLC4Net_SDK/Examples/OSLC4NetExamples.Server.NetCoreApi/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/OSLC4Net_SDK/OSLC4Net.Core.DotNetRdfProvider/RdfXmlMediaTypeFormatter.cs b/OSLC4Net_SDK/OSLC4Net.Core.DotNetRdfProvider/RdfXmlMediaTypeFormatter.cs index c005e3e..9e0d540 100644 --- a/OSLC4Net_SDK/OSLC4Net.Core.DotNetRdfProvider/RdfXmlMediaTypeFormatter.cs +++ b/OSLC4Net_SDK/OSLC4Net.Core.DotNetRdfProvider/RdfXmlMediaTypeFormatter.cs @@ -422,14 +422,14 @@ private Type GetMemberType(Type type) return null; } - private static bool ImplementsGenericType(Type genericType, Type typeToTest) + public static bool ImplementsGenericType(Type genericType, Type typeToTest) { var isParentGeneric = genericType.IsGenericType; return ImplementsGenericType(genericType, typeToTest, isParentGeneric); } - private static bool ImplementsGenericType(Type genericType, Type typeToTest, + public static bool ImplementsGenericType(Type genericType, Type typeToTest, bool isParentGeneric) { if (typeToTest == null) @@ -449,7 +449,7 @@ private static bool ImplementsGenericType(Type genericType, Type typeToTest, return ImplementsGenericType(genericType, typeToTest.BaseType, isParentGeneric); } - private static Type[] GetChildClassParameterArguments(Type genericType, Type typeToTest) + public static Type[] GetChildClassParameterArguments(Type genericType, Type typeToTest) { var isParentGeneric = genericType.IsGenericType; @@ -469,12 +469,12 @@ private static Type[] GetChildClassParameterArguments(Type genericType, Type typ } } - private static bool ImplementsICollection(Type type) + public static bool ImplementsICollection(Type type) { return type.IsGenericType && typeof(ICollection<>) == type.GetGenericTypeDefinition(); } - private class NonClosingStreamWriter : StreamWriter + public class NonClosingStreamWriter : StreamWriter { public NonClosingStreamWriter(Stream stream) : base(stream) diff --git a/OSLC4Net_SDK/OSLC4Net.Core.sln b/OSLC4Net_SDK/OSLC4Net.Core.sln index 9e7901b..4f43f29 100644 --- a/OSLC4Net_SDK/OSLC4Net.Core.sln +++ b/OSLC4Net_SDK/OSLC4Net.Core.sln @@ -1,4 +1,5 @@ -Microsoft Visual Studio Solution File, Format Version 12.00 + +Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.5.33516.290 MinimumVisualStudioVersion = 10.0.40219.1 @@ -19,23 +20,27 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OSLC4Net.Core.Query", "OSLC EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Examples", "Examples", "{798E9CDD-103C-4972-BC15-C5AAAF75C37D}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Oslc4NetExamples.Client", "Examples\Oslc4NetExamples.Client\Oslc4NetExamples.Client.csproj", "{96071622-1783-4274-80D0-C1A3E80FEEC8}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Oslc4NetExamples.Client", "Examples\Oslc4NetExamples.Client\Oslc4NetExamples.Client.csproj", "{96071622-1783-4274-80D0-C1A3E80FEEC8}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OSLC4Net.Core.DotNetRdfProvider", "OSLC4Net.Core.DotNetRdfProvider\OSLC4Net.Core.DotNetRdfProvider.csproj", "{DE666628-9716-42D1-A7D7-E584625A6E3B}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OSLC4Net.Core.DotNetRdfProvider", "OSLC4Net.Core.DotNetRdfProvider\OSLC4Net.Core.DotNetRdfProvider.csproj", "{DE666628-9716-42D1-A7D7-E584625A6E3B}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OSLC4Net.Core.JsonProvider", "OSLC4Net.Core.JsonProvider\OSLC4Net.Core.JsonProvider.csproj", "{0A5E0BBE-9591-4FCD-A91E-18F180434B49}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OSLC4Net.Core.JsonProvider", "OSLC4Net.Core.JsonProvider\OSLC4Net.Core.JsonProvider.csproj", "{0A5E0BBE-9591-4FCD-A91E-18F180434B49}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{5BCA08EA-BC25-4F9F-A825-8054E842619A}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OSLC4Net.ChangeManagementTest", "Tests\OSLC4Net.ChangeManagementTest\OSLC4Net.ChangeManagementTest.csproj", "{533433C7-2431-4937-B861-0286CAD60BCF}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OSLC4Net.ChangeManagementTest", "Tests\OSLC4Net.ChangeManagementTest\OSLC4Net.ChangeManagementTest.csproj", "{533433C7-2431-4937-B861-0286CAD60BCF}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OSLC4Net.Client.Tests", "Tests\OSLC4Net.Client.Tests\OSLC4Net.Client.Tests.csproj", "{0081D7DE-F525-4AF0-8F6B-8E4D4BD7F2B9}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OSLC4Net.Client.Tests", "Tests\OSLC4Net.Client.Tests\OSLC4Net.Client.Tests.csproj", "{0081D7DE-F525-4AF0-8F6B-8E4D4BD7F2B9}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OSLC4Net.Core.QueryTests", "Tests\OSLC4Net.Core.QueryTests\OSLC4Net.Core.QueryTests.csproj", "{4DFFC5EA-7D53-4AB7-804A-B8393CC85576}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OSLC4Net.Core.QueryTests", "Tests\OSLC4Net.Core.QueryTests\OSLC4Net.Core.QueryTests.csproj", "{4DFFC5EA-7D53-4AB7-804A-B8393CC85576}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OSLC4Net.Core.JsonProviderTests", "Tests\OSLC4Net.Core.JsonProviderTests\OSLC4Net.Core.JsonProviderTests.csproj", "{76B1D73F-6AAB-430A-BBAE-63B5DD8B3973}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OSLC4Net.Core.JsonProviderTests", "Tests\OSLC4Net.Core.JsonProviderTests\OSLC4Net.Core.JsonProviderTests.csproj", "{76B1D73F-6AAB-430A-BBAE-63B5DD8B3973}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OSLC4Net.Core.DotNetRdfProviderTests", "Tests\OSLC4Net.Core.DotNetRdfProviderTests\OSLC4Net.Core.DotNetRdfProviderTests.csproj", "{7EF256A2-DC83-4AF0-A608-C3CDC783D063}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OSLC4Net.Core.DotNetRdfProviderTests", "Tests\OSLC4Net.Core.DotNetRdfProviderTests\OSLC4Net.Core.DotNetRdfProviderTests.csproj", "{7EF256A2-DC83-4AF0-A608-C3CDC783D063}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OSLC4Net.Server.Providers", "OSLC4Net.Server.Providers\OSLC4Net.Server.Providers.csproj", "{CAC5AA53-9ED2-4D84-A8CF-4CC4B708EB04}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OSLC4NetExamples.Server.NetCoreApi", "Examples\OSLC4NetExamples.Server.NetCoreApi\OSLC4NetExamples.Server.NetCoreApi.csproj", "{FF342977-2AAA-45E9-8981-97CE0458E843}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -183,16 +188,34 @@ Global {7EF256A2-DC83-4AF0-A608-C3CDC783D063}.Release|Mixed Platforms.Build.0 = Release|Any CPU {7EF256A2-DC83-4AF0-A608-C3CDC783D063}.Release|x86.ActiveCfg = Release|Any CPU {7EF256A2-DC83-4AF0-A608-C3CDC783D063}.Release|x86.Build.0 = Release|Any CPU + {CAC5AA53-9ED2-4D84-A8CF-4CC4B708EB04}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CAC5AA53-9ED2-4D84-A8CF-4CC4B708EB04}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CAC5AA53-9ED2-4D84-A8CF-4CC4B708EB04}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {CAC5AA53-9ED2-4D84-A8CF-4CC4B708EB04}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {CAC5AA53-9ED2-4D84-A8CF-4CC4B708EB04}.Debug|x86.ActiveCfg = Debug|Any CPU + {CAC5AA53-9ED2-4D84-A8CF-4CC4B708EB04}.Debug|x86.Build.0 = Debug|Any CPU + {CAC5AA53-9ED2-4D84-A8CF-4CC4B708EB04}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CAC5AA53-9ED2-4D84-A8CF-4CC4B708EB04}.Release|Any CPU.Build.0 = Release|Any CPU + {CAC5AA53-9ED2-4D84-A8CF-4CC4B708EB04}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {CAC5AA53-9ED2-4D84-A8CF-4CC4B708EB04}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {CAC5AA53-9ED2-4D84-A8CF-4CC4B708EB04}.Release|x86.ActiveCfg = Release|Any CPU + {CAC5AA53-9ED2-4D84-A8CF-4CC4B708EB04}.Release|x86.Build.0 = Release|Any CPU + {FF342977-2AAA-45E9-8981-97CE0458E843}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FF342977-2AAA-45E9-8981-97CE0458E843}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FF342977-2AAA-45E9-8981-97CE0458E843}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {FF342977-2AAA-45E9-8981-97CE0458E843}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {FF342977-2AAA-45E9-8981-97CE0458E843}.Debug|x86.ActiveCfg = Debug|Any CPU + {FF342977-2AAA-45E9-8981-97CE0458E843}.Debug|x86.Build.0 = Debug|Any CPU + {FF342977-2AAA-45E9-8981-97CE0458E843}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FF342977-2AAA-45E9-8981-97CE0458E843}.Release|Any CPU.Build.0 = Release|Any CPU + {FF342977-2AAA-45E9-8981-97CE0458E843}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {FF342977-2AAA-45E9-8981-97CE0458E843}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {FF342977-2AAA-45E9-8981-97CE0458E843}.Release|x86.ActiveCfg = Release|Any CPU + {FF342977-2AAA-45E9-8981-97CE0458E843}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {B7097D9B-3362-4C14-B29F-CB2D6551677F} - EndGlobalSection - GlobalSection(TestCaseManagementSettings) = postSolution - CategoryFile = OSLC4Net.Core.vsmdi - EndGlobalSection GlobalSection(NestedProjects) = preSolution {96071622-1783-4274-80D0-C1A3E80FEEC8} = {798E9CDD-103C-4972-BC15-C5AAAF75C37D} {533433C7-2431-4937-B861-0286CAD60BCF} = {5BCA08EA-BC25-4F9F-A825-8054E842619A} @@ -200,5 +223,12 @@ Global {4DFFC5EA-7D53-4AB7-804A-B8393CC85576} = {5BCA08EA-BC25-4F9F-A825-8054E842619A} {76B1D73F-6AAB-430A-BBAE-63B5DD8B3973} = {5BCA08EA-BC25-4F9F-A825-8054E842619A} {7EF256A2-DC83-4AF0-A608-C3CDC783D063} = {5BCA08EA-BC25-4F9F-A825-8054E842619A} + {FF342977-2AAA-45E9-8981-97CE0458E843} = {798E9CDD-103C-4972-BC15-C5AAAF75C37D} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {B7097D9B-3362-4C14-B29F-CB2D6551677F} + EndGlobalSection + GlobalSection(TestCaseManagementSettings) = postSolution + CategoryFile = OSLC4Net.Core.vsmdi EndGlobalSection EndGlobal diff --git a/OSLC4Net_SDK/OSLC4Net.Server.Providers/OSLC4Net.Server.Providers.csproj b/OSLC4Net_SDK/OSLC4Net.Server.Providers/OSLC4Net.Server.Providers.csproj new file mode 100644 index 0000000..6ac5077 --- /dev/null +++ b/OSLC4Net_SDK/OSLC4Net.Server.Providers/OSLC4Net.Server.Providers.csproj @@ -0,0 +1,23 @@ + + + + net8.0 + false + OSLC4Net.Server.Providers + OSLC4Net.Server.Providers + + + + + + + + + + + + + + + + diff --git a/OSLC4Net_SDK/OSLC4Net.Server.Providers/OslcRdfInputFormatter.cs b/OSLC4Net_SDK/OSLC4Net.Server.Providers/OslcRdfInputFormatter.cs new file mode 100644 index 0000000..20fbc2c --- /dev/null +++ b/OSLC4Net_SDK/OSLC4Net.Server.Providers/OslcRdfInputFormatter.cs @@ -0,0 +1,12 @@ +using System.Text; +using Microsoft.AspNetCore.Mvc.Formatters; + +namespace OSLC4Net.Server.Providers; + +public class OslcRdfInputFormatter : TextInputFormatter +{ + public override async Task ReadRequestBodyAsync(InputFormatterContext context, Encoding encoding) + { + throw new NotImplementedException(); + } +} diff --git a/OSLC4Net_SDK/OSLC4Net.Server.Providers/OslcRdfOutputFormatter.cs b/OSLC4Net_SDK/OSLC4Net.Server.Providers/OslcRdfOutputFormatter.cs new file mode 100644 index 0000000..4b3db3f --- /dev/null +++ b/OSLC4Net_SDK/OSLC4Net.Server.Providers/OslcRdfOutputFormatter.cs @@ -0,0 +1,176 @@ +using System.Text; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Extensions; +using Microsoft.AspNetCore.Mvc.Formatters; +using Microsoft.AspNetCore.WebUtilities; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Primitives; +using Microsoft.Net.Http.Headers; +using OSLC4Net.Core.Attribute; +using OSLC4Net.Core.DotNetRdfProvider; +using OSLC4Net.Core.Model; +using VDS.RDF; +using VDS.RDF.Parsing; +using VDS.RDF.Writing; +using static OSLC4Net.Core.DotNetRdfProvider.RdfXmlMediaTypeFormatter; + +namespace OSLC4Net.Server.Providers; + +public class OslcRdfOutputFormatter : TextOutputFormatter +{ + public OslcRdfOutputFormatter() + { + SupportedMediaTypes.Add(OslcMediaType.TEXT_TURTLE_TYPE.AsMsNetType()); + SupportedMediaTypes.Add(OslcMediaType.APPLICATION_RDF_XML_TYPE.AsMsNetType()); + + SupportedEncodings.Add(Encoding.UTF8); + SupportedEncodings.Add(Encoding.Unicode); + } + + public override async Task WriteResponseBodyAsync(OutputFormatterWriteContext context, + Encoding selectedEncoding) + { + var httpContext = context.HttpContext; + var serviceProvider = httpContext.RequestServices; + + var logger = serviceProvider.GetRequiredService>(); + var buffer = new StringBuilder(); + + var type = context.ObjectType; + var value = context.Object; + var httpRequest = httpContext.Request; + + IGraph graph; + if (ImplementsGenericType(typeof(FilteredResource<>), type)) + { + var resourceProp = value.GetType().GetProperty("Resource"); + var actualTypeArguments = + GetChildClassParameterArguments(typeof(FilteredResource<>), type); + var objects = resourceProp.GetValue(value, null); + var propertiesProp = value.GetType().GetProperty("Properties"); + + if (!ImplementsICollection(actualTypeArguments[0])) + { + objects = new EnumerableWrapper(objects); + } + + if (ImplementsGenericType(typeof(ResponseInfo<>), type)) + { + //Subject URI for the collection is the query capability + // FIXME: should this be set by the app based on service provider info + var portNum = httpContext.Request.Host.Port; + string portString = null; + if (portNum == 80 || portNum == 443) + { + portString = ""; + } + else + { + portString = ":" + portNum; + } + + var descriptionAbout = httpRequest.Scheme + "://" + + httpRequest.Host + + portString + + httpRequest.Path; + + //Subject URI for the responseInfo is the full request URI + var responseInfoAbout = httpRequest.GetEncodedUrl(); + + var totalCountProp = value.GetType().GetProperty("TotalCount"); + var nextPageProp = value.GetType().GetProperty("NextPage"); + + graph = DotNetRdfHelper.CreateDotNetRdfGraph(descriptionAbout, + responseInfoAbout, + (string)nextPageProp.GetValue(value, null), + (int)totalCountProp.GetValue(value, null), + objects as IEnumerable, + (IDictionary)propertiesProp.GetValue(value, null)); + } + else + { + graph = DotNetRdfHelper.CreateDotNetRdfGraph(null, null, null, null, + objects as IEnumerable, + (IDictionary)propertiesProp.GetValue(value, null)); + } + } + else if (InheritedGenericInterfacesHelper.ImplementsGenericInterface( + typeof(IEnumerable<>), value.GetType())) + { + graph = DotNetRdfHelper.CreateDotNetRdfGraph(value as IEnumerable); + } + else if (type.GetCustomAttributes(typeof(OslcResourceShape), false).Length > 0) + { + graph = DotNetRdfHelper.CreateDotNetRdfGraph(new[] { value }); + } + else + { + graph = DotNetRdfHelper.CreateDotNetRdfGraph(new EnumerableWrapper(value)); + } + + // TODO: set the default + var contentType = context.ContentType; + await SerializeGraph(contentType, graph, httpContext.Response); + + //await httpContext.Response.WriteAsync(buffer.ToString(), selectedEncoding); + } + + + + private async Task SerializeGraph(StringSegment contentType, IGraph graph, + HttpResponse httpContextResponse) + { + IRdfWriter rdfWriter; + + var requestedMediaType = new MediaType(contentType); + + var requestedType = $"{requestedMediaType.Type}/{requestedMediaType.SubType}"; + + if (requestedType.Equals(OslcMediaType.APPLICATION_RDF_XML)) + { + var rdfXmlWriter = new RdfXmlWriter + { + UseDtd = false, PrettyPrintMode = false, CompressionLevel = 20 + }; + //turtlelWriter.UseTypedNodes = false; + + rdfWriter = rdfXmlWriter; + } + else if (requestedType.Equals(OslcMediaType.TEXT_TURTLE)) + { + var turtleWriter = new CompressingTurtleWriter(TurtleSyntax.W3C) + { + PrettyPrintMode = true, + CompressionLevel = WriterCompressionLevel.Minimal, + HighSpeedModePermitted = true + }; + + rdfWriter = turtleWriter; + } + else + { + //For now, use the dotNetRDF RdfXmlWriter for application/xml + //OslcXmlWriter oslcXmlWriter = new OslcXmlWriter(); + var oslcXmlWriter = new RdfXmlWriter + { + UseDtd = false, PrettyPrintMode = false, CompressionLevel = 20 + }; + + rdfWriter = oslcXmlWriter; + } + + var writer = new HttpResponseStreamWriter(httpContextResponse.BodyWriter.AsStream(), Encoding.UTF8); + rdfWriter.Save(graph, writer); + } +} + +public static class RdfOutputFormatterExtensions +{ + // REVISIT: can we drop one of the two? + public static MediaTypeHeaderValue AsMsNetType( + this System.Net.Http.Headers.MediaTypeHeaderValue oslcMediaType) + { + return MediaTypeHeaderValue.Parse(oslcMediaType.MediaType); + } +}