GithubHelp home page GithubHelp logo

Comments (7)

jeremydmiller avatar jeremydmiller commented on July 27, 2024

@Lele0037 That's failing up above because the ProjectB assembly cannot be found in your application when you run. Very easy fix is to make the direct reference to ProjectB from your application and go on with your day. Otherwise, I guess you could try to manually load the ProjectB assembly in your application before using Marten so that Assembly.Load() can function correctly.

from marten.

Lele0037 avatar Lele0037 commented on July 27, 2024

Hi @jeremydmiller , thank you for your response. Unfortunately, having ProjectB referenced in ProjectA is kind of a deal breaker: the whole purpose of this project is having ProjectA so that it does not know in advance which modules it will use (all the assemblies are loaded dynamically from a directory, so ProjectA cannot reference ProjectB).
I also tried adding an assembly pre-loading phase in Program.cs, like this:

var assembly = Assembly.LoadFrom("<path to dll>\\ProjectB.dll");
assembly.CreateInstance("ProjectB");

but it throws another error:

[2023-05-03T12:49:46.503Z] Error: System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation.
 ---> System.ArgumentException: ParameterExpression of type 'ProjectB.Test' cannot be used for delegate parameter of type 'ProjectB.Test'

   at System.Linq.Expressions.Expression.ValidateLambdaArgs(Type delegateType, Expression& body, ReadOnlyCollection`1 parameters, String paramName)
   at System.Linq.Expressions.Expression.Lambda[TDelegate](Expression body, String name, Boolean tailCall, IEnumerable`1 parameters)
   at System.Linq.Expressions.Expression.Lambda[TDelegate](Expression body, Boolean tailCall, IEnumerable`1 parameters)
   at Baseline.Expressions.LambdaBuilder.SetProperty[TTarget,TProperty](PropertyInfo property)
   at Baseline.Expressions.LambdaBuilder.Setter[TTarget,TMember](MemberInfo member)
   at Marten.Internal.Storage.DocumentStorage`2..ctor(StorageStyle storageStyle, DocumentMapping document)
   at Marten.Internal.Storage.QueryOnlyDocumentStorage`2..ctor(DocumentMapping document)
   at Marten.Generated.DocumentStorage.QueryOnlyTestDocumentStorage1398299618..ctor(DocumentMapping document)
   at Marten.Generated.DocumentStorage.TestProvider1398299618..ctor(DocumentMapping mapping)
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor)
   at System.Reflection.ConstructorInvoker.Invoke(Object obj, IntPtr* args, BindingFlags invokeAttr)

   --- End of inner exception stack trace ---

   at System.Reflection.ConstructorInvoker.Invoke(Object obj, IntPtr* args, BindingFlags invokeAttr)
   at System.Reflection.RuntimeConstructorInfo.Invoke(BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at System.RuntimeType.CreateInstanceImpl(BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture)
   at System.Activator.CreateInstance(Type type, Object[] args)
   at Marten.Internal.CodeGeneration.DocumentProviderBuilder.BuildProvider[T]()
   at Marten.Internal.ProviderGraph.StorageFor[T]()
   at Marten.Internal.Sessions.QuerySession.StorageFor[T]()
   at Marten.Internal.Sessions.DocumentSessionBase.store[T](IEnumerable`1 entities)
   at Marten.Internal.Sessions.DocumentSessionBase.Store[T](T[] entities)
   at ProjectB.Component1.SaveDoc() in <my path>\Component1.razor:line 18
   at ProjectB.Component1.SaveDoc() in <my path>\Component1.razor:line 21
   at ProjectB.Component1.<BuildRenderTree>b__0_0() in <my path>\Component1.razor:line 10
   at Microsoft.AspNetCore.Components.ComponentBase.CallStateHasChangedOnAsyncCompletion(Task task)
   at Microsoft.AspNetCore.Components.RenderTree.Renderer.GetErrorHandledTask(Task taskToHandle, ComponentState owningComponentState)

It seems that it has been able to load the assembly, but the loaded one is not compatible with the one it should be using for creating the document.

from marten.

jeremydmiller avatar jeremydmiller commented on July 27, 2024

You're in an older version, so the dependencies have changed underneath you. If you move up to Marten 6, I guess you could try a pull request to JasperFx.RuntimeCompiler's version of AttachAssembly() to try to find the assembly a different way than by name as it is today.

from marten.

Lele0037 avatar Lele0037 commented on July 27, 2024

@jeremydmiller I was already using version 6 actually. I tried implementing the following before setting Marten's IDocumentStore singleton:

var assemblyGenerator = new AssemblyGenerator();
assemblyGenerator.ReferenceAssembly(projectBAssembly);
var rules = new JasperFx.CodeGeneration.GenerationRules()
{
    TypeLoadMode = TypeLoadMode.Dynamic
};
assemblyGenerator.Compile(new JasperFx.CodeGeneration.GeneratedAssembly(rules));

I don't know if I'm using JasperFX right (I noticed that the AttachAssembly method was located in the Compile method I'm using above), but I'm still getting the same error (it's not able to find ProjectB assemblies).

from marten.

jeremydmiller avatar jeremydmiller commented on July 27, 2024

So that's what I meant for you to try, but it would need to be applied at the time Marten is trying to do the code compilation. So how are you dynamically discovering your extension assemblies again? I might have to ask you to create a repro project to know how to address this.

from marten.

Lele0037 avatar Lele0037 commented on July 27, 2024

Every "module" (i.e. every project with its own assembly) contains an object which implements an interface IModule (its actual structure does not matter). Once these helpers methods are defined,

        public static List<Assembly> GetAssemblies(string? path, bool iterate = false)
        {

            List<Assembly> allAssemblies = new List<Assembly>();

            var files = Directory.GetFiles(path ?? "", "*.dll", iterate ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly);

            foreach (string dll in files)
            {
                allAssemblies.Add(Assembly.LoadFile(dll));
            }

            var returnAssemblies = allAssemblies.Where(w => w.GetTypes().Any(a => a.GetInterfaces().Contains(typeof(IModule))));

            return returnAssemblies.ToList();
        }

        public static List<IModule> GetModules(string? path, bool iterate = false)
        {
            var modules = new List<IModule>();

            var assemblies = GetAssemblies(path, iterate);
            var types = assemblies.SelectMany(a => a.DefinedTypes.Where(x => x.GetInterfaces().Contains(typeof(IModule))));

            foreach (Type implementation in types)
            {
                if (!implementation.GetTypeInfo().IsAbstract)
                {
                    var instance = Activator.CreateInstance(implementation) as IModule;

                    modules.Add(instance);
                }
            }

            return modules;
        }

I execute them in my Program.cs as follows:

    public class Program
    {
        public static void Main(string[] args)
        {
            var builder = WebApplication.CreateBuilder(args);

            // Add services to the container.
            builder.Services.AddRazorPages();
            builder.Services.AddServerSideBlazor();

            string modulesPath = "<path where modules are located>"; 
            var modules = GetModules(modulesPath, true); // we look for our assemblies here
            foreach (var module in modules)
            {
                // objects that implement IModule do their stuff
            }

            builder.Services.AddMarten(options =>
            {
                options.Connection("<my connection string>");
                options.AutoCreateSchemaObjects = AutoCreate.All;
            });

            var app = builder.Build();

            // Configure the HTTP request pipeline.
            if (!app.Environment.IsDevelopment())
            {
                app.UseExceptionHandler("/Error");
            }

            app.UseStaticFiles();

            app.UseRouting();

            app.MapBlazorHub();
            app.MapFallbackToPage("/_Host");

            app.MapControllers();

            app.Run();
        }
    }

Hope that's clear enough.

from marten.

Lele0037 avatar Lele0037 commented on July 27, 2024

Hi again,
I finally made it work. I think I know what I was doing wrong: the assemblies were actually loaded twice by mistake. The first assembly load was taking place as above, in the Assembly.LoadFrom("<path to dll>\\ProjectB.dll"); bit. However, in my Blazor project I was also loading the assemblies here:

        <Router AppAssembly="@typeof(App).Assembly" AdditionalAssemblies="_assemblies">
            <Found Context="routeData">
                <RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
                <FocusOnNavigate RouteData="@routeData" Selector="h1" />
            </Found>
            <NotFound>
                <PageTitle>Not found</PageTitle>
                <LayoutView Layout="@typeof(MainLayout)">
                    <p role="alert">Sorry, there's nothing at this address.</p>
                </LayoutView>
            </NotFound>
        </Router>

@code {
    private List<Assembly> _assemblies = new();

    protected override void OnInitialized()
    {
        _assemblies = // here the assemblies where loaded for the second time by mistake, instead of being fetched from memory
        base.OnInitialized();
    }
}

This was causing the error I reported in my second response. Now everything works fine.
Thank you very much for your help.

from marten.

Related Issues (20)

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.