Codelux.ServiceStack 1.3.3

dotnet add package Codelux.ServiceStack --version 1.3.3                
NuGet\Install-Package Codelux.ServiceStack -Version 1.3.3                
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Codelux.ServiceStack" Version="1.3.3" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add Codelux.ServiceStack --version 1.3.3                
#r "nuget: Codelux.ServiceStack, 1.3.3"                
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install Codelux.ServiceStack as a Cake Addin
#addin nuget:?package=Codelux.ServiceStack&version=1.3.3

// Install Codelux.ServiceStack as a Cake Tool
#tool nuget:?package=Codelux.ServiceStack&version=1.3.3                

Codelux

Codelux is a collection of tools that simplify and abstract processes such as dependency injection, caching, configuration, mapping etc. Codelux.ServiceStack includes various ServiceStack helper libraries that make OrmLite model mapping, dependency injection and bootstrapping simple, elegant and clean. Additionally, Codelux.Plugins provides a base plugin framework for a pluggable architecture design.

Click here for the old BitBucket repository

Package Information

Tests
Tests
Package NuGet
Codelux Codelux
Codelux.Common Codelux
Codelux.ServiceStack Codelux
Codelux.Plugins Codelux

Installation

Install Codelux core library to your project:

PM> Install-Package Codelux

Install Codelux.Common library to your project

PM> Install-Package Codelux.Common

Install Codelux.ServiceStack library to your project

PM> Install-Package Codelux.ServiceStack

Install Codelux.Plugins library to your project

PM> Install-Package Codelux.Plugins

What does Codelux provide?

Codelux provides the following tools:

  • Monad types (F#-style Result and Option) that can contain one of two possible values
  • Thread-safe in-memory cache with expirable objects
  • Dependency registration modules for the Unity DI framework
  • A dependency container (inherits UnityContainer) that searches the current AppDomain for dependency modules to auto-register dependencies
  • An HTTP client to consume RESTful APIs (uses Newtonsoft.Json for serialization) - uses POCO request/responses
  • A generic abstract Mapper class that transforms one POCO to another based on user defined criteria
  • A thread-safe Runnable abstract class that enables task isolation (has condition status, i.e running/stopping/stopped)
  • A thread-safe repeating Runnable abstract class that enables task isolation and runs in a pre-defined period
  • A task executor generic class that resembles a workflow transformer. Accepts a POCO input and returnes a new one user-defined one
  • A type activator system that instantiates types based on user-defined logic
  • A simple and minimal logging framework that currently supports debug logging and LogDNA
  • A paging system which includes its own collection implementation that splits enumerables into pages of pre-defined size
  • Configuration source toolkit that helps implement configuration readers which can read configuration from various sources
  • Various generic utilities such as: Captcha provider, Base64 encoder, MD5 encoder, an e-mail sender service, a clock service and a password strength validator

Codelux.Common provides the following tools:

  • Dictionary extensions that provide a way to set items (create new or update if it exists) and add a range of key value pairs
  • Exception extensions that provide a way to get all inner exceptions or all exception messages (inspired by ServiceStack's GetInnermostException extension)
  • Object extenion that provides a fast nullity check (used for constructor params nullity checks) - throws ArgumentNullException if null
  • Struct extensions to box and unbox values quickly. Includes type checking when unboxing
  • Enum extension that reads a flag's DescriptionAttribute and returns its text
  • Various base generic request objects that could be used in a web service (Request, AuthenticatedRequest that provides username and other identity data) etc.
  • Various base generic response objects that could be used in a web service (ServiceResponse, ServiceErrorResponse)

Codelux.ServiceStack provides the following tools:

  • A core service component that inherits ServiceStack's Service and provides basic versioning
  • A ServiceStack exception handler that captures various common exceptions (TaskCancelledException, validation exceptions) and returns the appropriate, formatted response
  • Depenedency registration modules similar to the ones in Codelux but modified for compatibility with ServiceStack's IoC
  • OrmLite mapping helper that enables simple model property mapping to table columns easily.
  • A ServiceStack plugin that searches the AppDomain for OrmLite mappings and instantiates them (OrmLite requires instantiation of mappings to honor them)

Codelux.Plugins provides the following tools:

  • An agnostic plugin framework that can be implemented rapidly and fit most scenarios
  • Easily extensible to include additional functionality
  • A general plugin instance manager which loads plugin configurations and runs/stops plugins
  • JSON plugin configuration source which reads plugin configurations from JSON files and adds them to the instance manager

Why should I use this library?

My recommendation is not to use it as whole. I would advise taking the parts you need and implement them in your own project or compile a separate library one. The code is clean, reusable and easy to understand and therefore modification should be easy.

In addition to that, most critical parts have been tested as well. If you're a developer that uses ServiceStack for your web projects, the Codelux.ServiceStack library might be handy as it makes certain tasks trivial.

How to use the OrmLiteMapping feature:

  1. Define your model like the example below:
public class ExampleModel
{
    public Guid Id { get; set; }
    public Guid AnotherId { get; set; }
    public string StringValue { get; set; }
    public int IntegerValue { get; set; }
}
  1. Create a new class that inherits OrmLiteMapping around your model's type as shown below:
public class ExampleModelMapping : OrmLiteMapping<ExampleModel>
{
    public ExampleModelMapping()
    {
        MapToSchema("dbo");
        MapToTable("example_model");

        MapToColumn(x => x.Id, "id");
        MapToColumn(x => x.AnotherId, "another_id");
        MapToColumn(x => x.StringValue, "string_value");
        MapToColumn(x => x.IntegerValue, "integer_Value");
    }
}

Your mappings should be placed inside the constructor. The OrmLiteMappingFeature plugin will search the assembly for classes derived from OrmLiteMapping and will instantiate them. Therefore, all mappings are honored by OrmLite.

Other mapping functions:

*OrmLiteMapping.Ignore() - Ignores the given property and column
*OrmLiteMapping.AutoIncrement()- Maps a property to a column and marks it as auto increment

  1. Register OrmLiteMappingFeature plugin on your ServiceStack AppConfigurator:
appHost.Plugins.Add(new OrmLiteMappingFeature());

How to use role-based requests feature:

  1. Inherit IHasRole interface on your user model:
public class User : IHasRole
{
    public Guid Id { get; set; }
    public string Username { get; set; }
    public string Password { get; set; }
    public string Email { get; set; }
    public List<IRole> Roles { get; set; }
}

IHasRole adds a property of type List<IRole> to your model. These would be the roles your user has.

  1. Create roles by adding new classes that inherit IRole:
public class MemberRole : IRole
{
    public int Id { get; set; } = 0;
    public int Level { get; set; } = 1;
    public string Name { get; set; } = "Member";
}

public class ModeratorRole : IRole
{
    public int Id { get; set; } = 1;
    public int Level { get; set; } = 2;
    public string Name { get; set; } = "Moderator";
}

public class AdminRole : IRole
{
    public int Id { get; set; } = 2;
    public int Level { get; set; } = 3;
    public string Name { get; set; } = "Administrator";
}

Note: Make sure that when a role is higher, its level is also higher. An administrator has a higher level than a moderator in this example.

  1. Assign roles to your user by adding them to the List<IRole> collection:
User user = await _someRepository.GetAUser(); // This is pseudocode
user.Roles = new List<IRole>();
user.Roles.Add(new MemberRole());
user.Roles.Add(new ModeratorRole());

You may also store a user's roles in a database table and load them accordingly.

  1. Inherit and implement RoleValidatorBase:
public class RoleValidator : RoleValidatorBase
{
    public override Task<IHasRole> GetModelAsync(object key, CancellationChangeToken token = null)
    {
        // Your code here that retrieves a user model based on "key"
        // Key can be any data type, you may cast it as necessary
    }
}
  • GetModelAsync is a method which returns a user model based on its primary key. Feel free to retrieve it from any data source, such as an MsSql database or a Redis cache.
  • You may cast object key to your own primary key data type.
  • Additionally, you can validate if the primary key type is correct.
  1. Register your RoleValidator and the internal ProtectedRouteCollection to ServiceStack's IoC:
appHost.Container.RegisterAutoWiredAs<RoleValidator, IRoleValidator>();
appHost.Container.RegisterAutoWiredAs<ProtectedRouteCollection, IProtectedRouteCollection>();
  1. Add RoleBasedRequestsFeature plugin to ServiceStack's plugins:
appHost.Plugins.Add(new RoleBasedRequestsFeature());

You can additionally configure the error message and the status code on a failed request like so:

appHost.ConfigurePlugin<RoleBasedRequestsFeature>(x =>
{
    x.UnauthorizedRequestErrorMessage = "Your custom error message";
    x.UnauthorizedRequestStatusCode = HttpStatusCode.Forbidden;
});
  1. Register protected routes on ServiceStack using the AddProtectedRoute extension method:
appHost.AddProtectedRoute<ExampleRequestModel>("/api/request", new ModeratorRole(), ApplyTo.Get);

Notes:

  • AddProtectedRoute is an extension on IAppHost
  • The given role on AddProtectedRoute is the minimum required role to run the request. This means that a user with ModeratorRole or above, based on the role's level, will be able to run the request.

Conclusion

I wrote this library in my free time to simplify some tasks that were repeated. Feel free to use it as you please.
Any additions, fixes or enhancements are welcome, please submit a pull request if you want to make a change.
If you have any questions, please feel free to create an issue on GitHub and I will try to respond as soon as I can.

Contributing

Found an issue?

Please report any issues you have found by creating a new issue. We will review the case and if it is indeed a problem with the code, I will try to fix it as soon as possible. I want to maintain a healthy and bug-free standard for our code. Additionally, if you have a solution ready for the issue please submit a pull request.

Submitting pull requests

Before submitting a pull request to the repository please ensure the following:

  • Your code follows the naming conventions suggested by Microsoft
  • Your code works flawlessly, is fault tolerant and it does not break the library or aspects of it
  • Your code follows proper object oriented design principles. Use interfaces!

Your code will be reviewed and if it is found suitable it will be merged. Please understand that the final decision always rests with me. By submitting a pull request you automatically agree that I hold the right to accept or deny a pull request based on my own criteria.

Contributor License Agreement

By contributing your code to Codelux you grant Nikolas Andreou a non-exclusive, irrevocable, worldwide, royalty-free, sublicenseable, transferable license under all of Your relevant intellectual property rights (including copyright, patent, and any other rights), to use, copy, prepare derivative works of, distribute and publicly perform and display the Contributions on any licensing terms, including without limitation: (a) open source licenses like the MIT license; and (b) binary, proprietary, or commercial licenses. Except for the licenses granted herein, You reserve all right, title, and interest in and to the Contribution.

You confirm that you are able to grant us these rights. You represent that you are legally entitled to grant the above license. If your employer has rights to intellectual property that you create, You represent that you have received permission to make the contributions on behalf of that employer, or that your employer has waived such rights for the contributions.

You represent that the contributions are your original works of authorship and to your knowledge, no other person claims, or has the right to claim, any right in any invention or patent related to the contributions. You also represent that you are not legally obligated, whether by entering into an agreement or otherwise, in any way that conflicts with the terms of this license.

Nikolas Andreou acknowledges that, except as explicitly described in this agreement, any contribution which you provide is on an "as is" basis, without warranties or conditions of any kind, either express or implied, including, without limitation, any warranties or conditions of title, non-infringement, merchantability, or fitness for a particular purpose.

Product Compatible and additional computed target framework versions.
.NET net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 is compatible.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
1.3.3 168 8/6/2023
1.3.2 159 7/8/2023
1.3.1 146 6/16/2023
1.3.0 181 4/17/2023
1.2.9 171 4/16/2023
1.2.8 174 4/14/2023
1.2.7 223 3/18/2023
1.2.6 301 1/2/2023
1.2.5 301 11/27/2022
1.2.4 293 11/26/2022
1.2.3 297 11/25/2022
1.2.2 305 11/7/2022
1.2.1 425 7/15/2022
1.2.0 408 4/11/2022
1.1.0 433 3/6/2022
1.0.0 420 1/22/2022