Giter VIP home page Giter VIP logo

solidservices's Introduction

Highly Maintainable Web Services

The Highly Maintainable Web Services project is a reference architecture application for .NET that demonstrates how to build highly maintainable web services.

This project contains no documentation, just code. Please visit the following article for the reasoning behind this project:

For more background about the used design, please read the following articles:

This project contains the following Web Service projects that all expose the same set of commands and queries:

  • WCF. This project exposes command and query messages through a WCF SOAP service, while all messages are specified explicitly through a WSDL. This exposes an explicit contract to the client, although serialization and deserialization of messages is quite limited in WCF, which likely causes problems when sending and receiving messages, unless the messages are explicitly designed with the WCF-serialization constraints in mind. The Client project sends queries and commands through the WCF Service. Due to the setup, it gives full integration into the WCF pipeline, which includes security, logging, encryption, and authorization.
  • ASP.NET 'Classic' 4.8 Web API (includes a Swagger API). This project exposes commands and queries as REST API through the System.Web.Http stack (the 'legacy' ASP.NET Web API) of .NET 4.8. REST makes the contract less explicit, but allows more flexibility over a SOAP service. It uses JSON.NET as serialization mechanism, which allows much flexibility in defining command and query messages. Incoming requests are mapped to HttpMessageHandlers, which dispatch messages to underlying command and query handlers. In doing so, it circumvents a lot of the Web API infrastructure, which means logging and security might need to be dealt with separately. This project uses an external NuGet library to allow exposing its API through an OpenAPI/Swagger interface.
  • ASP.NET Core 3.1 Web API. This project exposes commands and queries as REST API through ASP.NET Core 3.1's Web API. REST makes the contract less explicit but allows more flexibility over a SOAP service. Just as the previous 'classic' Web API project, it uses JSON.NET as serialization mechanism, which allows much flexibility in defining command and query messages. Incoming requests are mapped to specific Middleware, which dispatches messages to underlying command and query handlers. In doing so, it circumvents a lot of the ASP.NET Core Web API infrastructure, which means logging and security might need to be dealt with separately. This project has no support for exposing its API through OpenAPI/Swagger.
  • ASP.NET Core 6 Web API (includes a Swagger API). This project exposes commands and queries as REST API through ASP.NET Core 6 Minimal API. The project uses .NET 6's System.Text.Json as serialization mechanism, which is the built-in mechanism. It is less flexible compared to JSON.NET, but gives superb performance. This project makes full use of the new Minimal API functionality and maps each query and command to a specific URL. This allows full integration into the ASP.NET Core pipeline, including logging, security, and OpenAPI/Swagger. There is some extra code added to expose command and query XML documentation summaries through as part of the operation's documentation. Due to limitations in the Minimal API framework, queries only support HTTP POST operations.

solidservices's People

Contributors

dependabot[bot] avatar dotnetjunkie avatar stevengopmo avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

solidservices's Issues

Report progress and cancel long running queries

Have you ever come accross the need to report progress of a query execution?
I have a long running query which constists of 3 main blocks to execute. As IQuery returns a query result when it is finished, I see no possibility to report intermediate results.

The opposite would be, how to cancel a running query. As I understand it, queries are kind of fire and forget wait until they are finished. With the possibility to have a contract-serializer sitting somewhere in the pipeline I doubt that using a CancellationToken would work?

Generic query handler that looks up entity by primary key

I'm using your IQueryHandler pattern with good results. Command and query handlers are basically my data access layer and I would like to always use a query handler when querying the database for something. Even if it is for simply looking up an object by its primary key. I have however been unable to get rid of the use of repositories for one use case: looking up a domain object by its primary key.

I can of course create a specific class that implements IQueryHandler for each domain class I want to be able to look up by primary key, but that seems unnecessary since I can do it in a generic way using a repository.

This is the generic repository I would like to replace:

private readonly MyDbContext context;
private readonly DbSet<T> dbSet;

public EfRepository(MyDbContext dbContext)
{
    this.context = dbContext;
    this.dbSet = dbContext.Set<T>();
}

public async Task<T> GetByIdAsync(params object[] id)
{
    return await dbSet.FindAsync(id);
 }

To replace this I defined the following query class:

public class EntityByPrimaryKeyQuery<T> : IQuery<T> where T : class
{
    public EntityByPrimaryKeyQuery(int id)
    {
        Id = id;
    }

    public int Id { get; set; }
}

I then defined the following query handler class:

public class EntityByPrimaryKeyQueryHandler<T>
    : IQueryHandler<EntityByPrimaryKeyQuery<T>, T>
    where T : class
{
    private readonly MyDbContext dbContext;

    public EntityByPrimaryKeyQueryHandler(MyDbContext dbContext)
    {
        this.dbContext = dbContext;
    }

    public async Task<T> HandleAsync(EntityByPrimaryKeyQuery<T> query)
    {
        var dbSet = dbContext.Set<T>();

        return await dbSet.FindAsync(query.Id);
    }
 }

I use Simple Injector and I normally register all my IQueryHandler implementations with one line:

container.Register(typeof(IQueryHandler<,>), AppDomain.CurrentDomain.GetAssemblies());

I then try to inject an instance of the IQueryHandler in my service MyService for a specific domain class like this:

IQueryHandler<EntityByPrimaryKeyQuery<MyDomainClass>, MyDomainClass> queryHandler

When I do this, Simple Injector gives me the following error:

The constructor of type MyService contains the parameter with name 'queryHandler' and type IQueryHandler<EntityByPrimaryKeyQuery<MyDomainClass>, MyDomainClass> that is not registered. Please ensure IQueryHandler<EntityByPrimaryKeyQuery<MyDomainClass>, MyDomainClass> is registered, or change the constructor of MyService . Note that there exists a registration for a different type IQueryHandler<TQuery, TResult> while the requested type is IQueryHandler`2[[EntityByPrimaryKeyQuery<EntityByPrimaryKeyQuery<MyDomainClass>,MyDomainClass>.'

Is what I am trying to achieve possible? If so, what am I doing wrong?

Failed

Enjoyed viewing solidservices, but i judge a book by its cover, or if the app runs ok investigate unfortunately
I was unable to successfully run app, always times out?

Any suggestion?

Well I did learn something, I was a amazed to see you implement System.Data.Entity

Coding style is clean, a solution would be nice so I can investigate your code more

Always prove the code works

Peter

[Q] async/await Handlers

Can you elaborate on your design decisions, why you chose the sync version instead of the async way, please?
sync:
TResult Handle(TQuery query);
async:
Task<TResult> Handle(TQuery query);

Where are the Web API controllers?

Hi,

I've been looking at your solidservices project and noticed that the web api project doesn't define any controllers and it looks like you're probably doing some trickery for it to automatically generate the controllers from the commands and queries. Could you explain this a little or link me to the blog post about it?

I'm guessing you usually try and keep each controller to doing as little as possible and most of the time that controller revolves around the command, as this is what I've been doing with my MVC? The advantage of this is that I don't have constructor over injection.

Kind Regards, Richard

Controllerless WebApi documentation with multiple xml doc files

Great work here! One question, regarding your Controllerless API library and xml doc files...

I see that you are copying the xml documentation file to the App_Data directory of the web api project in a post-build step. I have separated out my commands/queries into separate class libraries to facilitate re-use. In that case, how can I get the api explorer to see my xml comments from multiple assemblies? If the ControllerlessActionFilter took an array of xml doc files, it would be perfect. Perhaps something like below? Have you worked around this already?

var appDataPath = HostingEnvironment.MapPath("~/App_Data");
var xmlDocFiles = Directory.GetFiles(appDataPath, "*.xml").ToList();
foreach(var xmlFile in xmlDocFiles)
{
     c.IncludeXmlComments(xmlFile);
}
var filter = new ControllerlessActionOperationFilter(xmlDocFiles);
c.OperationFilter(() => filter);

How to write unit tests with CQRS?

Hi Steven,

I'm struggling to find a good unit testing example when using CQRS and just wondering if you've any plans on adding some unit tests to the solution?

Failing that, what parts of the system would you usually expect to see tests for when using CQRS? If you could recommend any good resources on the web in this area, that would be good too.

Thanks.

No DI Container? See the Pure DI branch

For anyone interested, there's now a The PureDI branch that shows a Pure DI implementation of the repository. This means that instead of using Simple Injector, the projects use no DI Container whatsoever, but instead demonstrate how to apply these patterns using DI, while hand wiring all object graphs using plain old new statements.

Solid Services License

Could you attach a license to this repository so its clear what your intent is for others to use? I'd like to borrow some snippets with your permission.

Thoughts on Exposing IQueryable<T> from repository layer

This question is a follow up to https://twitter.com/dot_NET_Junkie/status/1287991487440068608

I see code where IQueryable is exposed from Repository layer.

public interface IRepository
{
    IQueryable<T> Query<T>();
}

It is very handy in many cases, especially when using external libraries that leverage that interface, for example some plugins that sort/filter and bind to ui elements. (e.g https://hotchocolate.io/docs/10.0.0-rc.3/filters) at the same time, it looks like it is tightly coupled with the DB Backend only.

  1. Entity Framework itself seems to be an implementation of Repository and Unit of Work patterns. If we wrap it behind another repository is there any benefit other than the fact that it is decoupled from EF.

Accepting JSON Arrays as input parameters.

Hi,

I have a situation where for the command contract, in one of the parameters I would like to accept JSON Array.

Command Contract 
{
  "clientId": 309,
  "jsonKey": 1,
  "functionalKey": 2,
  "leaseData": ""
}

In leaseData field I need to accept a JSON array like below -

[{"EffectiveDate":"1/2/2015",
    "EndingDate":"1/3/2017","GIA":"1","GIAMeasure":"Ping","NIA":"1",
    "NIAMeasure":"Ping","TenureName":"Red Run 1",
    "TenureId":"MD-OWM-004","AreaType":"Archive","Comments":"Test","Vacant":"Yes"
}]

How can this be handled. Please suggest.

Thanks,
JPB

How to reuse get-by-id queries?

hey Steven,

I'm currently undergoing my refactoring on the company framework so it uses CQRS. Like I said we are using entity framework as our O/RM. A few things questions that I don't know how to solve has arisen:

  1. I'm not really keen on having loads of QueryById types of queries. Is there a way we can have a QueryById<Entity> to avoid those?

  2. On the writing side, when using entity framework, we typically get the object from the database first and then update the object. But if our repositories for the writing side only have update, delete and create available, how can we do this? not only that but there can be situations where we need to make a query (or queries) before updating for whatever reasons. How do you handles these on CQRS?

thanks again for being so active and helping everyone out :)

Swashbuckle with ASP.NET Core

Hi,
did you already figure out, how to handle the new way of swashbuckle to look for controllers, when run with asp.net core?
Maybe this is no problem if the filter

var filter = new ControllerlessActionOperationFilter(xmlCommentsPath);
c.OperationFilter(() => filter);

would be working. But for this, a replacement for the new Asp.net core ApiExplorer is needed.

No operations defined in spec - Swagger

Hi Steven,

I am building a solution skeleton using the "ASP.NET Core 6 Web API"

But when opening the swagger index page, I am getting "No operations defined in spec!" message.

Here is a full content of the xml file:

<?xml version="1.0"?>
<doc>
    <assembly>
        <name>CSP.Contract</name>
    </assembly>
    <members>
        <member name="T:CSP.Contract.Commands.CSP.Project.OpenProjectCommand">
            <summary>
            Open a new Pss Project use case.
            </summary>
        </member>
        <member name="P:CSP.Contract.Commands.CSP.Project.OpenProjectCommand.EnName">
            <summary>
            Project Name (in English)
            </summary>
        </member>
        <member name="P:CSP.Contract.Commands.CSP.Project.OpenProjectCommand.ArName">
            <summary>
            Project Name (in Arabic)
            </summary>
        </member>
        <member name="P:CSP.Contract.Commands.CSP.Project.OpenProjectCommand.Description">
            <summary>
            Project Description
            </summary>
        </member>
        <member name="T:CSP.Contract.IQuery`1">
            <summary>
            Defines a query message.
            </summary>
            <typeparam name="TResult"></typeparam>
        </member>
    </members>
</doc>

I expect the swagger page shows one api. It does not.

How to version Commands?

Hey Steven,

I think I'm having a problem versioning my commands. I currently have two UI projects (Desktop & Web) sharing the same command/query handler web service. The command/query contracts are deployed to the Desktop and Web UI projects via NuGet, so they can choose when to upgrade separately. When I add a new property to a command, I currently do no tracking of this version change in the command type itself.
The new command property will generally be mapped to an entity property and stored in the database. If you are using an older version of the contract, the web service will default the new property value to something during Json deserialization. So if the Web UI project decides to use the new version and the Desktop project does not, the command coming from the Desktop project could overwrite the value of the new command property with the default value. I think what'd I'd like to have happen is if you are using an older version of the contract, these defaulted values are ignored during entity mapping. I'm wondering if you ever came across this issue? Or have any advice on how to solve it?

Thanks for any advice,
Brett

how to handle massive queries

I am in the situation where I have to create a kind of dynamic query with loads and loads of optional cols/properties. These are cols to add to a data export. Assume some 1000 cols are possible. But also only 1 col - just how the user is about to configure the export. These cols are sourced somewhere in lots of different tables which need to get joined.
So definetly not something for hard coded query classes. :(

what I came up with is this use case:

  • enable query results with variable columns in its result set
  • messages should be typed and not be strings
class TableA {
    string A1 {get;set;}
    string A2 {get;set;}
}

class TableB {
    string B1 {get;set;}
    string B2 {get;set;}
}

class TableC {
    string C1 {get;set;}
    string C2 {get;set;}
}

//some kind of multilevel tree to handle the loads of options
class AllCols {
    TableA A {get;set;}
    TableB B {get;set;}
    TableC C {get;set;}
}

class GetColsQuery<AllCols> {
    //maybe some filter
}

class GetReportResult<Report> {
    //like: "get report with cols A.A1, B.B2, C.C1"

    //with strings 
    List<string> ColsForReport {get;set;} //<- filled with nameof()-style helper

   // with dummy tree-object  
    AllCols ColsForReport {get;set;} //<- all fields to include are set to not-null 
   
   //with json:  build a json object and parse it back onto a full object with 
    jsonNet.populateObject or jObject.ToObject<TableA>()
}

class Report {
    //some result stuff
}
  • with List<string>: it's a string list. not typesafe
  • with dummy tree-object: maybe? dummy values feel rather smelly
  • with json: json.net has the possibility to populate objects from an incomplete json representation.
    json is the language of webApi, but before and after webApi its just strings - like above.

Do you have any other idea on how to solve this?

Rate-limiting

I am using some of your command/query abstractions proposed in this reference architecture to great success - thanks very much for sharing this!

I have a question. I would like to introduce a way to rate-limit certain commands (purposely only allow a configurable rate of execution per command). For example, a command handler which uses an http client to invoke a sensitive API that limits how many requests per minute. I am wondering how you would suggest implementing this capability using an architecture very similar to your reference architecture?

I am considering using a decorator that would only be applied to certain command handlers, which is injected with a singleton manager of sorts that keeps track of the last time of execution, and would delay until the next interval. This doesn't seem very elegant, so I am hoping you have a better idea?

Thanks!

Complex validations

Dear Steven,
I hope my question finds you well,

We had complex validations on the commands, for example: one field is required based on the value of other fields.

In your provided SOLID Services template there is DataAnnotationsValidator. I wounder if we can extend it or do something to enable the complex validation I mentioed.

Please assit us.
Yours,
Anas

Is it possible to have a create and update command that uses the same command type?

Hi,

I started playing round with the command query pattern and wanted it to work in a crud like manner. So I started by prototyping a create and update commands that would use the same DTO command but this then confuses Simple Injector as it doesn't know which one to instantiate as they use the same command. In my mind it seems that the create and update commands would use the same DTO and the only way to get around this I can think of is to use inheritance for separate commands or to define to separate types with the same properties?

Bellow is some basic code demonstrating what I've done. Starting with the DTO that is used as my commands.

class AddressDto
{
    public int Id { get; set; }
    public string Line1 { get; set; }
    public string Line2 { get; set; }
    public string Postcode { get; set; }
}

Both of my handlers

class CreateAddressHandler : ICommandHandler<AddressDto>
{
    public void Handle(AddressDto command)
    {
        //Do something
    }
}
class UpdateAddressHandler : ICommandHandler<AddressDto>
{
    public void Handle(AddressDto command)
    {
        //Do something
    }
}

The creation of the handler

class Program
{
    static readonly Container container;

    static Program()
    {
        container = new Container();

        container.Register(typeof(ICommandHandler<>), AppDomain.CurrentDomain.GetAssemblies());
    }
    static void Main(string[] args)
    {
        var service = container.GetInstance<CreateAddressHandler>();
        AddressDto command = new AddressDto();
        //Fill up our command and then use it
        service.Handle(command);
    }
}

Command and Query Responsibility Segregation pattern

Migrated from: https://solidservices.codeplex.com/discussions/574373

LauriSaar wrote:

Hi,

There is one great blog post about Command-query separation which is located here.

I've played with this architecture for some time and one question pops up: how would you handle sorting through IQuery<TResult>?

Let’s say that I have MVC webapp that needs server-side sorting and I want that sorting and paging happens in DB.

Behind these interfaces it is matter of type parameters if single entity’s property must be sortable at DB level. But as soon as I want to sort by more than one property it might get somewhat unintuitive. And I haven’t figured out simple way to pass ordering of multi sorting (not sort direction).

At first I passed lambda of Expression<Func<TEntity,TKey>> together with sort direction, used separate class for that. Overall it got quite verbose because all of those type parameters, but it worked fine, Linq2Entity’s IQueryable<>.OrderBy() was happy.

But as soon as I moved to multi sorting I found out that I cannot use IEnumerable< Expression<Func<TEntity,TKey>>> because TKey can vary with different properties. Tried with Expression<Func<TEntity,object>> and dynamic -- Linq2Entity’s IQueryable<>.OrderBy() was unhappy.

Next thing that worked was “public SortDirection? SortAmount {get;set}”-like properties on query implementation. SortDirection is enum with 2 constants. Handler has “if” statements to check for which properties to call .OrderBy().

But this solution’s drawback is that I haven’t found intuitive way to pass ordering of .OrderBy() calls.

Implementing row-based security

This discussion was originally posted on CodePlex as discussion 566865 but that original discussion is not available any longer.

Binding exception when using delegatinghandler from a library

Hi,

I'm sure this is something fundamental but I get the following error when I use the QueryDelegatingHandler from a library dll instead of directly in my webapi projects.

System.AggregateException: One or more errors occurred. ---> Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: 'object' does not contain a definition for 'HandleAsync'
   at CallSite.Target(Closure , CallSite , Object , Object )
   at System.Dynamic.UpdateDelegates.UpdateAndExecute2[T0,T1,TRet](CallSite site, T0 arg0, T1 arg1)
   at goPMO.Common.WebApi.QueryDelegatingHandler.<SendAsync>d__3.MoveNext() in C:\projects\gopmo-common\source\goPMO.Common.WebApi\QueryDelegatingHandler.cs:line 67
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Web.Http.Cors.CorsMessageHandler.<SendAsync>d__2.MoveNext()
   --- End of inner exception stack trace ---
   at System.Threading.Tasks.Task`1.GetResultCore(Boolean waitCompletionNotification)
   at System.Threading.Tasks.Task`1.get_Result()
   at goPMO.Common.WebApi.Security.DummyAuthenticationHandler.<>c.<SendAsync>b__2_0(Task`1 task) in C:\projects\gopmo-common\source\goPMO.Common.WebApi\Security\DummyAuthenticationHandler.cs:line 28
   at System.Threading.Tasks.ContinuationResultTaskFromResultTask`2.InnerInvoke()
   at System.Threading.Tasks.Task.Execute()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Web.Http.HttpServer.<SendAsync>d__24.MoveNext()
---> (Inner Exception #0) Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: 'object' does not contain a definition for 'HandleAsync'
   at CallSite.Target(Closure , CallSite , Object , Object )
   at System.Dynamic.UpdateDelegates.UpdateAndExecute2[T0,T1,TRet](CallSite site, T0 arg0, T1 arg1)
   at goPMO.Common.WebApi.QueryDelegatingHandler.<SendAsync>d__3.MoveNext() in C:\projects\gopmo-common\source\goPMO.Common.WebApi\QueryDelegatingHandler.cs:line 67
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Web.Http.Cors.CorsMessageHandler.<SendAsync>d__2.MoveNext()<---

The same exact code works fantastic when included in the actual WebApi. At first I thought it had something to do with types e.g. where type is in thisassembly vs. whatever type I actually asked for but that doesn't appear to be the case.

For reference the code that is erroring is

        try
        {
            var query = DeserializeQuery(request, queryData, info.QueryType);
            var result = await handler.HandleAsync(query);
            return HttpResponseMessageExtensions.FromResult(request, result);
        }
        catch (Exception exception)
        {
            var response = WebApiErrorResponseBuilder.CreateErrorResponseOrNull(exception, request);
            if (response != null)
                return response;

            throw;
        }

Line 67 from the stack trace is the throw; line. Obviously the error is occuring at the ' var result = await handler.HandleAsync(query);' where query is an object instead of the type I want.

Any thoughts?

Query Pattern and loading navigation properties

Hi Steven,

Here is my base abstract class that represents a query pattern that I then inherit from for each type of query.

public abstract class QueryBase<TResult> where TResult : class
{
    protected Data.ApplicationDBContext DbContext { get; }
    
    protected QueryBase(Data.ApplicationDBContext dbContext)
    {
        this.DbContext = dbContext;
    }
    
    public abstract TResult Retrieve();
}

Here is a simple example of a query. Not that it is eagerly loading related data every time.

public class GetProcedureTemplateHeaderQuery : QueryBase<ProcedureTemplateHeader>
{
    public int TemplateId { get; set; }
    
    public GetProcedureTemplateHeaderQuery(ApplicationDBContext context) : base(context) { }
    
    public override ProcedureTemplateHeader Retrieve()
    {
        this.DbContext.ProcedureTemplateHeaders
            .Include(m => m.ProcedureTemplateStages.Select(e =>
                e.ProcedureTemplateDetails.Select(d => d.ProcedureTemplateQuestions)))
            .Include(c => c.ProcedureTemplateStages.Select(a =>
                a.ProcedureTemplateDetails.Select(b => b.ProcedureTemplateGrouping)))
            .SingleOrDefault(m => m.Id == this.TemplateId);
    }
}

Here is my ProcedureTemplateHeader entity. A Template Header is made up of many stages and those stages are each made up of many details.

public class ProcedureTemplateHeader
{
    public ProcedureTemplateHeader()
    {
        this.ProcedureTemplateStages = new HashSet<ProcedureTemplateStage>();
    }

    [Key]
    public int Id { get; set; }

    [Required, StringLength(255)]
    public string Name { get; set; }

    public ICollection<ProcedureTemplateStage> ProcedureTemplateStages { get; set; }
}
public class ProcedureTemplateStage
{
    public ProcedureTemplateStage()
    {
        this.ProcedureTemplateDetails = new HashSet<ProcedureTemplateDetail>();
    }

    [Key]
    public int Id { get; set; }

    public int HeaderId { get; set; }
    
    [ForeignKey("HeaderId")]
    public ProcedureTemplateHeader ProcedureTemplateHeader { get; set; }

    // Other data
    public ICollection<ProcedureTemplateDetail> ProcedureTemplateDetails { get; set; }
}
public class ProcedureTemplateDetail
{
    public ProcedureTemplateDetail()
    {
        this.ProcedureTemplateQuestions = new HashSet<ProcedureTemplateQuestion>();
        this.ProcedureTemplateGrouping = new HashSet<ProcedureTemplateDetailGroup>();
    }

    [Key]
    public int Id { get; set; }

    public int StageId { get; set; }
    
    [ForeignKey("StageId")]
    public ProcedureTemplateStage ProcedureTemplateStage { get; set; }

    // Other data
    public ICollection<ProcedureTemplateQuestion> ProcedureTemplateQuestions { get; set; }
    public ICollection<ProcedureTemplateDetailGroup> ProcedureTemplateGrouping { get; set; }
}

Here is how my query is then consumed in my controller

public TestController : Controller

    // GET: Test
    public ActionResult Index(int id)
    {
        var qry = new GetProcedureTemplateHeaderQuery(WebAppHelper.GetContext())
        {
            TemplateId = id
        };
        
        var header = qry.Retrieve();

        // Do some work with my header

        return this.View(header);
    }
}

What I am curious about is that every time I use GetProcedureTemplateHeaderQuery's retrieve it will get all of the data associated and not just the header, the trouble with this is that the consumer might only need the header and not need to know about the stages and details of the stage. What is the best way of approaching this?

Commands depending on Other Queries to work - Lookup Tables

Hello Steven,
I hope you are healthy, and doing well.

Some of my Commands needs to do some data to work. For example, a CreateNewFacility Command depends on querying Locations; so that, When sending CreateNewFacilityCommand for handling it contains LocationId.

I am thinking of building a commands dependency list. When the client (Web, Mobile app) logs in the system, it first call GetCommandsDependencyListQuery. Then before calling a command it sees if there any Query to send to the server.

Your assistance is highly appreciated.

SOLID Services - the Python way

Hi Steven,
I search the web for the Python way of doing SOLID services.

I found no hits. Do you have any information in this regards, please?

ASP.NET core sample throws exception because of missing IHttpContextAccessor registration

While playing around with SimpleInjector and the sample for ASP.Core I found that the sample is not working in it's current state.

When running the sample for ASP.NET Core the following exception is thrown

System.InvalidOperationException
  HResult=0x80131509
  Message=The configuration is invalid. Creating the instance for type ICommandHandler<CreateOrderCommand> failed. The constructor of type Bootstrapper.HttpContextPrincipal contains the parameter with name 'httpContextAccessor' and type IHttpContextAccessor that is not registered. Please ensure IHttpContextAccessor is registered, or change the constructor of Bootstrapper.HttpContextPrincipal.
  Source=SimpleInjector
  StackTrace:
   at SimpleInjector.InstanceProducer.VerifyExpressionBuilding()
   at SimpleInjector.Container.VerifyThatAllExpressionsCanBeBuilt(InstanceProducer[] producersToVerify)
   at SimpleInjector.Container.VerifyThatAllExpressionsCanBeBuilt()
   at SimpleInjector.Container.VerifyInternal(Boolean suppressLifestyleMismatchVerification)
   at SimpleInjector.Container.Verify()
   at WebCoreService.Bootstrapper.Bootstrap(Container container, IApplicationBuilder app) in C:\Users\klaas.hoffmann\Source\Repos\solidservices\src\WebCoreService\Bootstrapper.cs:line 29
   at WebCoreService.Startup.Configure(IApplicationBuilder app, IHostingEnvironment env) in C:\Users\klaas.hoffmann\Source\Repos\solidservices\src\WebCoreService\Startup.cs:line 55

Inner Exception 1:
ActivationException: The constructor of type Bootstrapper.HttpContextPrincipal contains the parameter with name 'httpContextAccessor' and type IHttpContextAccessor that is not registered. Please ensure IHttpContextAccessor is registered, or change the constructor of Bootstrapper.HttpContextPrincipal.

According to the great documentation I found that a call to container.AutoCrossWireAspNetComponents is missing.

I have changed the sample and try to make a pull request.

It's again time to say "thank you Steven (and the team) for your brilliant work regarding SimpleInjector (including the documentation!)".
I've worked with many DI container, but no other product is as good as the one you created.
I don't know how often I've had a look in the documentation (and now your book too) to do things in the right way.

Commands depending on other commands when using the decorator pattern for transaction

Hi,

I've been using your TransactionCommandHandlerDecorator and I came across a small problem when using this in conjunction with a command that has a dependency on another command as it is creating a second transaction block for the other command when I want it to share the same transaction?

Here is some code to demonstrate the problem.

Public Class TransactionCommandHandlerDecorator(Of TCommand)
    Implements ICommandHandler(Of TCommand)

    Private ReadOnly _decorated As ICommandHandler(Of TCommand)
    Private ReadOnly _context As ApplicationDBContext

    Public Sub New(context As ApplicationDBContext, decorated As ICommandHandler(Of TCommand))
        _context = context
        _decorated = decorated
    End Sub

    Public Sub Handle(command As TCommand) Implements ICommandHandler(Of TCommand).Handle
        Using transaction = _context.Database.BeginTransaction()
            Try
                _decorated.Handle(command)
                transaction.Commit()
            Catch ex As Exception
                transaction.Rollback()
                Throw
            End Try
        End Using
    End Sub
End Class
Public Class CreateProcedureTemplateDetailQuestionTypeHandler
    Implements ICommandHandler(Of CreateProcedureTemplateDetailQuestionTypeCommand)

    Private ReadOnly _context As ApplicationDBContext
    Private ReadOnly _handler As ICommandHandler(Of CreateProcedureTemplateDetailCommand)

    Public Sub New(context As ApplicationDBContext, handler As ICommandHandler(Of CreateProcedureTemplateDetailCommand))
        _context = context
        _handler = handler
    End Sub

    Public Sub Handle(command As CreateProcedureTemplateDetailQuestionTypeCommand)
        Implements ICommandHandler(Of CreateProcedureTemplateDetailQuestionTypeCommand).Handle
        _handler.Handle(command.DetailCommand)

        'Do other stuff specific to this command
    End Sub
End Class

But once I call handle inside of CreateProcedureTemplateDetailQuestionTypeHandler.Handle() I get an exception as it tries to create another transaction scope. What is the best way of dealing with this, should I just new up instance inside of the CreateProcedureTemplateDetailQuestionTypeHandler and not use DI for that case?

Authentication with Commands?

Hi,
in https://www.cuttingedge.it/blogs/steven/pivot/entry.php?id=92 you once wrote:

... However, in the case of logging in a user, I don't think that's really suited for a command, since you are really asking a question here (while doing a side effect). Instead, I would use an IAuthorizationService or something like that.

On a WebApi or WCF app, Commands and Queries are the only way to communicate from the Gui to the backend. Is there something else that would fit for the login use case (user has to enter username and password to authenticate, or user has to scan his/her id card to authenticate)?

Talking about passwords: how do you handle sensitive data on commands? Do you encrypt them clientside before transferring them to the server?

Mediator and DI

Hello @dotnetjunkie ,

I'm trying to better understand the DynamicQueryProcessor.cs implementation and the IQueryProcessor interface. I get how it's helpful in reducing dependencies.

However, I'm trying to make sense of it in light of DI principles mentioned in your book, and I'm hoping you can help me with this:

The execute method in DynamicQueryProcessor is going to a DI container. My understanding is that any time you go to a DI container outside of the Composition Root, the Service Locator Pattern is effectively used. It also seems to be that usage of IQueryProcessor has some of the drawbacks of a Service Locator i.e. hidden dependencies. This makes unit testing more challenging.

Is this mediator effectively a Service Locator, or am I missing something here? What are your thoughts?

Bug in KnownTypesDataContractResolver

I've been playing around with the wcf client and found, that the knowTypes detection is too aggressive:

 this.knownTypes = (
                from type in types.Distinct()
                group type by type.Name into g
                select g.First())
                .ToDictionary(GetName);

This line is faulty: group type by type.Name into g

type.Name causes types like the following to be treated as the same:
GetUserRightsQuery : IQuery<Paged<UserRight>>
GetUsersQuery : IQuery<Paged<User>>
because type.Name returns Paged1 (or similar) for both of them.

What was the intention of the grouping?
When I remove .Name I get all necessary types to deserialize the wcf result.

EventSourcing thoughts

Hi @dotnetjunkie ,
Great job with this project! One question: Have you ever thought about expanding your architecture to include event sourcing? I think it is common practice to include event sourcing with CQRS, and I am curious how you would implement that here, or if you have done that with this stack before?

Thanks!

ExceptionFilterAttribute doesn't get hit

I've noticed that my Custom ExceptionFilterAttribute doesn't get hit when using this approach to WebApi. Maybe that's the reason you have a try catch in the DelegatingHandlers? Do you know why the normal filtering mechanism doesn't work with this approach? In general, I'm kind of anti try/catch and I think the built-in WebApi approach is generally pretty decent.

Of course, this one small place for catching isn't bad; I guess I'm curious if there's a technical reason.

Comparison with MediatR library

Hello Steven

Please could you check my reasoning.

I'm trying to compare the popular MediatR library with your separate Command and Query Mediator pattern. My colleagues are keen on adopting MediatR and I want to understand the subtle differences.

CQS separately handles Commands and Queries, with an optional Mediator for Queries to reduce dependencies as they are usually more numerous. Commands are usually more isolated, so less issue with over injection, thus do not require the additional Mediator which would obfuscate dependencies. Having both Command and Query dependencies abstracted to a Mediator might be good for decoupling, but could be considered an antipattern in hiding dependencies.

MediatR has less distinction between Command and Queries. Confusingly both are called Requests, and does not enforce void/unit on Commands. However some Commands might be permitted to return a Result type if desired for flexibly handling success or failure in a more functional way. Relying on a library instead of rolling your own is a dependency in itself however it might be easier for other developers to understand.

Then there is .Net Core’s FromServices attribute for injecting directly to Actions and relieving the Constructor overloading problem and perhaps pointing towards the simpler explicit Query injection. Thus having the freedom to roll your own is more flexible.

Thanks for an inspiring DI book, articles and comment responses.

Regards

Stephen

How to use IQueryHandler when Handle() doesn't need any query params?

Hi,

I want to use the IQueryHandler for a GetAllTemplates() but it demands a IQuery Type to be associated with it so that it can be passed to the handle function, but this handler does not need any parameters and I would be creating an empty query type. How do I get around this?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.