Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Having a projection configuration in a class named Projection leads to compilation exception #3184

Closed
mrnustik opened this issue May 8, 2024 · 3 comments · Fixed by #3186

Comments

@mrnustik
Copy link

mrnustik commented May 8, 2024

Hi, I have put my projection configuration classes inside the projected class and named them Projection. Marten finds the projection well, but unfortunately, I have run into a compilation exception from the projection code generation. I have managed to track down the code, that generates it but unfortunately, I was not able to create the fix myself.

Projection registration

storeOptions.Projections.Add<AccountListInformation.Projection>(ProjectionLifecycle.Inline)

Projection code

public class AccountListInformation
{
    public Guid Id { get; set; }
    public AccountId AccountId { get; private set; }
    public string Name { get; private set; }
    public decimal Balance { get; private set; }

    public void Apply(AccountCreated accountCreated)
    {
        Id = accountCreated.Id.Value;
        AccountId = accountCreated.Id;
        Name = accountCreated.Name;
        Balance = 0;
    }
    
    public class Projection : SingleStreamProjection<AccountListInformation>
    {
        public Projection()
        {
            ProjectEvent<AccountCreated>((i, e) => i.Apply(e));
        }
    }
}

Exception output along with the code generation error

System.InvalidOperationException: Compilation failures!

CS0103: The name 'projection' does not exist in the current context

Code:

// <auto-generated/>
#pragma warning disable
using Expensifier.API.Accounts.GetAccountsById;
using Marten;
using Marten.Events.Aggregation;
using Marten.Internal.Storage;
using System;
using System.Linq;

namespace Marten.Generated.EventStore
{
    // START: ProjectionLiveAggregation260415182
    public class ProjectionLiveAggregation260415182 : Marten.Events.Aggregation.SyncLiveAggregatorBase<Expensifier.API.Accounts.GetAccountsById.AccountListInformation>
    {
        private readonly Expensifier.API.Accounts.GetAccountsById.AccountListInformation.Projection _projection;

        public ProjectionLiveAggregation260415182(Expensifier.API.Accounts.GetAccountsById.AccountListInformation.Projection projection)
        {
            _projection = projection;
        }


        public System.Action<Expensifier.API.Accounts.GetAccountsById.AccountListInformation, Expensifier.API.Accounts.Domain.AccountCreated> ProjectEvent1 {get; set;}


        public override Expensifier.API.Accounts.GetAccountsById.AccountListInformation Build(System.Collections.Generic.IReadOnlyList<Marten.Events.IEvent> events, Marten.IQuerySession session, Expensifier.API.Accounts.GetAccountsById.AccountListInformation snapshot)
        {
            if (!events.Any()) return snapshot;
            var usedEventOnCreate = snapshot is null;
            snapshot ??= Create(events[0], session);;
            if (snapshot is null)
            {
                usedEventOnCreate = false;
                snapshot = CreateDefault(events[0]);
            }

            foreach (var @event in events.Skip(usedEventOnCreate ? 1 : 0))
            {
                snapshot = Apply(@event, snapshot, session);
            }

            return snapshot;
        }


        public Expensifier.API.Accounts.GetAccountsById.AccountListInformation Create(Marten.Events.IEvent @event, Marten.IQuerySession session)
        {
            return null;
        }


        public Expensifier.API.Accounts.GetAccountsById.AccountListInformation Apply(Marten.Events.IEvent @event, Expensifier.API.Accounts.GetAccountsById.AccountListInformation aggregate, Marten.IQuerySession session)
        {
            switch (@event)
            {
                case Marten.Events.IEvent<Expensifier.API.Accounts.Domain.AccountCreated> event_AccountCreated1:
                    aggregate.Apply(event_AccountCreated1.Data);
                    ProjectEvent1.Invoke(aggregate, event_AccountCreated1.Data);
                    break;
            }

            return aggregate;
        }

    }

    // END: ProjectionLiveAggregation260415182
    
    
    // START: ProjectionInlineHandler260415182
    public class ProjectionInlineHandler260415182 : Marten.Events.Aggregation.AggregationRuntime<Expensifier.API.Accounts.GetAccountsById.AccountListInformation, System.Guid>
    {
        private readonly Marten.IDocumentStore _store;
        private readonly Marten.Events.Aggregation.IAggregateProjection _projection1;
        private readonly Marten.Events.Aggregation.IEventSlicer<Expensifier.API.Accounts.GetAccountsById.AccountListInformation, System.Guid> _slicer;
        private readonly Marten.Internal.Storage.IDocumentStorage<Expensifier.API.Accounts.GetAccountsById.AccountListInformation, System.Guid> _storage;
        private readonly Expensifier.API.Accounts.GetAccountsById.AccountListInformation.Projection _projection2;

        public ProjectionInlineHandler260415182(Marten.IDocumentStore store, Marten.Events.Aggregation.IAggregateProjection __projection1, Marten.Events.Aggregation.IEventSlicer<Expensifier.API.Accounts.GetAccountsById.AccountListInformation, System.Guid> slicer, Marten.Internal.Storage.IDocumentStorage<Expensifier.API.Accounts.GetAccountsById.AccountListInformation, System.Guid> storage, Expensifier.API.Accounts.GetAccountsById.AccountListInformation.Projection __projection2) : base(store, projection, slicer, storage)
        {
            _store = store;
            _projection1 = __projection1;
            _slicer = slicer;
            _storage = storage;
            _projection2 = __projection2;
        }


        public System.Action<Expensifier.API.Accounts.GetAccountsById.AccountListInformation, Expensifier.API.Accounts.Domain.AccountCreated> ProjectEvent1 {get; set;}


        public override async System.Threading.Tasks.ValueTask<Expensifier.API.Accounts.GetAccountsById.AccountListInformation> ApplyEvent(Marten.IQuerySession session, Marten.Events.Projections.EventSlice<Expensifier.API.Accounts.GetAccountsById.AccountListInformation, System.Guid> slice, Marten.Events.IEvent evt, Expensifier.API.Accounts.GetAccountsById.AccountListInformation aggregate, System.Threading.CancellationToken cancellationToken)
        {
            switch (evt)
            {
                case Marten.Events.IEvent<Expensifier.API.Accounts.Domain.AccountCreated> event_AccountCreated2:
                    aggregate ??= CreateDefault(evt);
                    ProjectEvent1.Invoke(aggregate, event_AccountCreated2.Data);
                    return aggregate;
            }

            return aggregate;
        }


        public Expensifier.API.Accounts.GetAccountsById.AccountListInformation Create(Marten.Events.IEvent @event, Marten.IQuerySession session)
        {
            return null;
        }

    }

    // END: ProjectionInlineHandler260415182
    
    
}


   at JasperFx.RuntimeCompiler.AssemblyGenerator.Generate(String code)
   at JasperFx.RuntimeCompiler.AssemblyGenerator.Compile(GeneratedAssembly generatedAssembly, IServiceVariableSource services)
   at JasperFx.RuntimeCompiler.CodeFileExtensions.InitializeSynchronously(ICodeFile file, GenerationRules rules, ICodeFileCollection parent, IServiceProvider services)
   at Marten.Events.Projections.GeneratedProjection.<generateIfNecessary>g__generateIfNecessaryLocked|21_0(<>c__DisplayClass21_0&)
   at Marten.Events.Projections.GeneratedProjection.generateIfNecessary(DocumentStore store)
   at Marten.Events.Projections.GeneratedProjection.Marten.Events.Projections.IProjectionSource.Build(DocumentStore store)
   at Marten.Events.Projections.ProjectionOptions.<>c__DisplayClass23_0.<BuildInlineProjections>b__1(IProjectionSource x)
   at System.Linq.Enumerable.SelectArrayIterator`2.Fill(ReadOnlySpan`1 source, Span`1 destination, Func`2 func)
   at System.Linq.Enumerable.SelectArrayIterator`2.ToArray()
   at Marten.Events.Projections.ProjectionOptions.BuildInlineProjections(DocumentStore store)
   at Marten.Events.EventGraph.<>c__DisplayClass16_0.<.ctor>b__2()
   at System.Lazy`1.ViaFactory(LazyThreadSafetyMode mode)
   at System.Lazy`1.ExecutionAndPublication(LazyHelper executionAndPublication, Boolean useDefaultConstructor)
   at System.Lazy`1.CreateValue()
   at Marten.Events.EventGraph.ProcessEventsAsync(DocumentSessionBase session, CancellationToken token)
   at Marten.Internal.Sessions.DocumentSessionBase.SaveChangesAsync(CancellationToken token)
   at Marten.Internal.Sessions.DocumentSessionBase.SaveChangesAsync(CancellationToken token)
   at Expensifier.API.Accounts.CreateAccount.CreateAccountCommand.Handler.Execute(CreateAccountCommand command, CancellationToken cancellationToken) in F:\Development\Expensifier\api\Expensifier.API\Accounts\CreateAccount\CreateAccountCommand.cs:line 29
   at Expensifier.API.Accounts.Endpoints.<>c.<<AddAccountEndpoints>b__0_0>d.MoveNext() in F:\Development\Expensifier\api\Expensifier.API\Accounts\Endpoints.cs:line 18
--- End of stack trace from previous location ---
   at Microsoft.AspNetCore.Http.RequestDelegateFactory.ExecuteTaskResult[T](Task`1 task, HttpContext httpContext)
   at Microsoft.AspNetCore.Http.RequestDelegateFactory.<>c__DisplayClass102_2.<<HandleRequestBodyAndCompileRequestDelegateForJson>b__2>d.MoveNext()
--- End of stack trace from previous location ---
   at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
   at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)
@mrnustik
Copy link
Author

mrnustik commented May 8, 2024

The issue seems to be in the underlying code generation code from the JasperFx.CodeGeneration repository. I have created an issue there as well.

@jeremydmiller
Copy link
Member

@mrnustik So for a quick work around, literally call your Projection class any other valid C# name other than Projection

@mrnustik
Copy link
Author

mrnustik commented May 9, 2024

@jeremydmiller thanks for such a quick response and fix. I have already changed my projection name, but will test it once it gets out. 🙂

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants