Hello to everyone interlinked with OSLC!
Today I am thrilled to announce OSLC4Net release version 0.5.0! It is a pretty big release and includes significant improvements. Highlights:
- Every PR in OSLC4Net is tested against OSLC OP Reference Implementation (RM & CM servers).
- Major changes to ensure every operation in
OslcClient
is available as an async method. - Your “plain old C# objects” (POCOs) used to model OSLC resources can now use C# properties instead of Java-style getters/setters.
OSLC4Net.Domains.RequirementsManagement
was added.- Extended properties were fixed, you can add any properties to your objects beyond what’s defined in OSLC specs.
If you are impatient, go to NuGet to grab the package identifiers and look at the example project. For more details, read on (or look at the change log).
Testing against Reference Implementation
OSLC4Net had integration tests against the Change Management server from the Reference Implementation before. However, it was cumbersome to run those tests and it was done only occasionally (usually, prior to a release).
Thanks to advances in the dotnet ecosystem, NET Aspire makes this much easier. OSLC4Net now features an Aspire-based fixture for xunit. In other news, OSLC4Net is now fully migrated from a mix of MSTest and xunit v2 to xunit v3!
Better testing enabled us to make some refactoring and changes we were shying away from in the past, namely to the DotNetRdfHelper
, responsible for the object-graph mapping between POCOs and RDF.
In other news, our test matrix now includes Windows, Ubuntu x86, as well as Ubuntu ARM + NET 8 (current LTS), 9 (latest release), and 10 (preview builds of the next LTS, scheduled for release in November 2025).
Async OslcClient
There are currently two clients in OSLC4Net (not counting an attempt to rewrite a client using RestSharp to get a semi-free OAuth 1.0a support - this one is on pause mainly because I think we should only focus on OAuth 2, contributions welcome!): OslcClient
and OslcRestClient
. The OslcRestClient
has been deprecated for a while, but was heavily used in ServiceProviderRegistryClient
, while OslcClient
was lacking in terms of async support that’s essential to the modern .NET apps.
No more! OslcClient
is now fully async (the remaining non-async methods are annotated [Obsolete]
and slated for removal in the next release). Additionally, ServiceProviderRegistryClient
was updated to use OslcClient
.
One major difference between two clients is that OslcRestClient
required a new instance for each URI you wanted to interact with - tedious and inefficient. OslcClient
methods take the resource URI as a parameter, just like in Eclipse Lyo.
Property-based POCOs
The initial version of OSLC4Net was written in a Java-heavy style, which is jarring to dotnet developers and requires a lot of boilerplate. OSLC4Net was updated to support OSLC annotations directly on C# properties. Compare the old code:
ChangeRequest changeRequest = new();
changeRequest.AddContributor(new Uri("http://myserver/mycmapp/users/bob"));
changeRequest.AddCreator(new Uri("http://myserver/mycmapp/users/bob"));
changeRequest.AddDctermsType(ChangeManagement.Type.Defect.ToString());
changeRequest.SetDescription("Invalid installation instructions indicating invalid patches to be applied.");
changeRequest.SetDiscussedBy(new Uri("http://example.com/bugs/2314/discussion"));
changeRequest.SetInstanceShape(new Uri("http://example.com/shapes/defect"));
changeRequest.AddRelatedChangeRequest(new Link(new Uri("http://myserver/mycmapp/bugs/1235"), "Bug 1235"));
changeRequest.SetSeverity(Severity.Major.ToString());
changeRequest.SetShortTitle("Bug 2314");
changeRequest.SetStatus("InProgress");
changeRequest.AddSubject("doc");
changeRequest.AddSubject("install");
changeRequest.SetTitle("Invalid installation instructions");
changeRequest.AddTracksRequirement(new Link(new Uri("http://myserver/reqtool/req/34ef31af")));
changeRequest.AddTracksRequirement(new Link(new Uri("http://remoteserver/reqrepo/project1/req456"), "Requirement 456"));
var creation = await GetCreationAsync(mediaType, Constants.TYPE_CHANGE_REQUEST);
OslcRestClient oslcRestClient = new(Formatters,
creation,
mediaType);
var addedChangeRequest = await oslcRestClient.AddOslcResourceAsync(changeRequest);
to the new code:
Requirement resource = new()
{
Identifier = "REQ-001",
Title = "Test requirement",
Constrains =
[new Uri("http://example.com/REQ-002"), new Uri("http://example.com/REQ-003")],
Creator = [new Uri("https://github.com/berezovskyi")],
ExtendedProperties =
{
[DCTerms.Description] = "A sample description",
[PROV.AtLocation] =
new Uri("http://dbpedia.org/resource/Stockholm"),
[DC.Language] = "en-GB"
}
};
var creation = await GetCreationAsync(MediaType, Constants.TYPE_REQUIREMENT)
.ConfigureAwait(true);
var newRequirement = await TestClient
.CreateResourceAsync(creation, resource, MediaType)
.ConfigureAwait(true);
var createdResource = newRequirement.Resources?.SingleOrDefault();
Did you notice all the little differences? There are a few we did not talk about yet:
- The test is using the newly released OSLC4Net.Domains.RequirementsManagement. It provides
Requirement
andRequirementCollection
generated directly from OSLC RM 2.1 shapes. - OSLC4Net Core now ships with vocabulary helper classes designed to make your life easier when working with extended properties beyond what’s defined in OSLC shapes. OSLC4Net 0.5.0 includes the following vocabularies:
- W3C PROV-O vocab used for tracking provenance
- NASA QUDT used for quantities and units
- W3C SKOS used to relate taxonomical terms
- FOAF, used in OSLC to point to agents, often
foaf:Person
. - Dublin Code Metadata Initiative (DCMI) DC Terms aka ISO 15836-2:2019 (preferred), as well DC Elements aka ISO 15836-1:2017 (legacy)
- W3C LDP
- There was also a bug where extended properties using predicates from unknown vocabs (i.e., those with prefixes unknown to the DotNetRDF) could not be deserialized. This is now fixed! OSLC4Net RefImpl is able to handle such extended properties and round-trip them.
The vocabularies above were generated using a couple of Python scripts. Feel free to generate more vocabs and OSLC shapes domains and contribute PRs!
New OslcResponse class
One of the sharp edges in Lyo Client has been a gap between a bare Jena graph and a nice single POJO when processing a response. OSLC4Net sets out to provide a JAX-RS-like Response object that has extra OSLC-specific information handy when processing a response. Meet OslcResponse:
public sealed class OslcResponse<T> where T : IResource
{
public List<T>? Resources { get; private set; } = default;
public HttpResponseMessage? ResponseMessage { get; private set;}
public HttpStatusCode? StatusCode { get; private set; }
public Graph? Graph { get; private set; } = default;
public Error? ErrorResource { get; private set; } = null;
}
Key features:
- handles multiple OSLC resources in one response
- exposes underlying HTTP response (and the status directly for convenience)
- exposes the DotNetRDF graph
- exposes the OSLC Error object for error status codes where one can be deserialized from the graph.
Happy hacking,
Andrew