-
Notifications
You must be signed in to change notification settings - Fork 2.4k
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
Adding custom content part exception under edit #11314
Comments
This means that you created a ContentPart and that this ContentPart is missing a Shape View to use for the Admin UI BuildEditorAsync() method. Of course, it will fail if there is no Shape View created for it to display. The ContentPart cannot be rendered without a View. |
I'm not sure what that means. AFAIK it does have views out of the box, but I could be wrong about that. Obviously with the exception, something about that is askew. |
Can you show me your Startup.cs file code? |
Module or app? Module... public class Startup : StartupBase
{
public override void ConfigureServices(IServiceCollection services)
{
services.Configure<TemplateOptions>(options =>
{
options.MemberAccessStrategy.Register<AssemblyCredentialsPartViewModel>();
});
services
.AddContentPart<AssemblyCredentialsPart>()
.UseDisplayDriver<AssemblyCredentialsPartDisplayDriver>()
.AddHandler<AssemblyCredentialsPartHandler>()
;
services.AddScoped<IContentTypePartDefinitionDisplayDriver, AssemblyCredentialsPartSettingsDisplayDriver>();
services.AddScoped<IDataMigration, Migrations>();
}
public override void Configure(IApplicationBuilder builder, IEndpointRouteBuilder routes, IServiceProvider serviceProvider)
{
routes.MapAreaControllerRoute(
name: "Home"
, areaName: "Path.To.Cms.Module"
, pattern: "Home/Index"
, defaults: new { controller = "Home", action = "Index" }
);
}
} App: public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
static AssemblyCredentialsInfo CreateAssemblyCredentialsInfo(IServiceProvider _)
=> new AssemblyCredentialsInfo(typeof(Startup).Assembly)
;
services.AddSingleton<IAssemblyCredentialsInfo>(CreateAssemblyCredentialsInfo);
;
services.AddOrchardCms(config =>
{
config.RegisterStartup<Path.To.Cms.Module.Startup>();
});
}
public void Configure(IApplicationBuilder app, IHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseStaticFiles();
app.UseOrchardCore(config =>
{
config.UseSerilogTenantNameLogging();
});
const bool poweredByOrchardCore = true;
app.UsePoweredByOrchardCore(poweredByOrchardCore);
}
} |
I've at least got the part listing with the other assets, which is a start. Just the editor is not connected for whatever reason. |
Everything seems appropriate at first sight. |
Only at first sight. I get the exception however. I definitely had to wire things a bit differently than I first thought in order for the |
Does it run the Startup.cs file at all?
This part here, not sure it is necessary. |
Ok, I think I'm starting to understand the issue. static AssemblyCredentialsInfo CreateAssemblyCredentialsInfo(IServiceProvider _)
=> new AssemblyCredentialsInfo(typeof(Startup).Assembly)
;
services.AddSingleton<IAssemblyCredentialsInfo>(CreateAssemblyCredentialsInfo);
;
services.AddOrchardCms(config =>
{
config.RegisterStartup<Path.To.Cms.Module.Startup>();
}); All of this won't work. because you are registering it at the app level while it needs to be registered at each tenant. Though, when you create an Orchard Core module, its services are registered for each tenant that are enabled. So, the Startup.cs file is ran for each tenant context. |
App versus tenant? Not sure what you mean. 'Tenant' just means an app, does it not? Multi-tenant meaning you have 1+ apps running alongside each other? |
For a bit of additional context, in the part handler, I do this, which draws from the DI. protected internal IAssemblyCredentialsInfo Info { get; }
// TODO: TBD: or at least this is the direction we think we need to go...
public AssemblyCredentialsPartHandler(IAssemblyCredentialsInfo assyCredentialsInfo)
{
Info = assyCredentialsInfo;
}
public override Task InitializingAsync(InitializingContentContext context, AssemblyCredentialsPart part)
{
part.Show = true;
// // TODO: TBD: may need to be serializable, relay into the part instance...
// part.Info = Info;
return Task.CompletedTask;
} |
A tenant is an instance of a host. You can have, let's say Main tenant : domain.com Each of these tenants will have their own database configuration and will be an entire new Orchard Core instance. |
Right, I get that, which is just another web app. i.e. |
And in each of these tenants, we can enable Orchard Core modules. So, the tenant themselves manages the services that they are using. Here, if you register your Interface at the App level then I'm not sure the module from TenantA will know that the service exists. It expects to find it at the Tenant level, not the app level. /cc @jtkech |
Ok, we made some progress on that one. I will let @jtkech comment. I need to go for now. Time to get off the computer. It is the week-end ... |
No problem, I appreciate the assist. |
Well I do know this much at any rate, the info bits and such are being wired and connecting. |
Considering other topics, this is turning into a semi-major block for us. Perhaps the fix is straightforward, just need a bit of verification, guidance, etc, if you please. However, also not sure we want the liquid after all; rather I think we prefer the Razor, for a whole host of reasons, not the least of which we think it is better supported up and down the entire tool chain. |
At least prima facie, i.e. on its face, Occam's razor, should |
Okay, that was not the issue. I really do not know what the issue is, but it seems like some glue is missing, perhaps, in the module, or perhaps even deeper into the OC/CMS framework itself. |
Any ideas what might be causing this issue? Or what the resolution ought to be? White or black box... Transparent is preferred, OOB; but crossing that bridge, of course. Thank you... |
Can you check Lombiq's tutorial that explains how to create custom Parts and their view? |
Reviewing that, thank you. |
In and of itself, I can piece that much together. However, how are the dots connected with a CMS web app? |
@mwpowellhtx some unordered info Yes, we have the main app running in a main container / pipeline, and each tenant (having their own settings e.g. url prefix) runs in an isolated container / pipeline, we have at least a Then a module may need a manifest.cs file to define its features, as I remember you don't need it if you have only one main feature (the module code itself) but better to have one. Then your module project, to be recognized as a module / theme, needs to reference the Notice that a module also has the structure of a "micro" app with its controllers / drivers / views / models, and this is the set of enabled module features that composes a given tenant "application". Then you need a module startup (as you did) so that the module can collaborate to the building of a given tenant in which it is enabled, when the tenant container is building the module startup When you register services at the app level, there are cloned to child tenant containers unless some as routing services that mutate global collections on startup, so because any tenant may be built at any time while other are running, each tenant needs its isolated routing services. We also filter some middlewares to prevent them from being executed multiple times, e.g. the default ones registered at the app level by aspnet, and so on. But most of the time, what is intended to be used by a given tenant is registered at the tenant level through module startups that are enabled for this tenant. So you don't need at the app level to do.
That said, at the app level we have helpers that allows to register things at the tenant level, like a module / feature startup would do but then that would be enabled for all tenants. E.g. we have
Returning back to the original issue,it seems that you already created driver / handler and the needed migration to define your custom part, so looks like you are very close to have an operational content Part. When we create a Part composed of Fields through the Admin UI, we don't need a related part shape view template, and each field already has their oob shapes e.g. for editing, but when you define a part by code, as soon as you register a display driver and that drives a given shape whose default name uses the part name (can be overridden), you also need to provide the related view file. Notice that the same driver can combine multiple shapes with different view models, in that case each one should have a related shape view (a shape can be defined by .cs code). And for each shape your driver can define different alternates view templates, the first one found by starting from the end of the list will be used. By convention template names don't use Finally you need to enable your module that should be listed under the Admin Features page, if not yet done automatically through a setup recipe. |
@jtkech Maybe I am missing something there, it seems like more dots to connect following the |
@jtkech Circling back on this one. The module itself, in and of itself, I think the parts are connected properly, out of the box, and with the bits that I want to lift into the part for rendering purposes. I need to see the app side of things. How is that connected with the (an?) app? |
From the App perspective, I tried this, with and without public void ConfigureServices(IServiceCollection services)
{
services.AddOrchardCms(configure =>
{
configure.RegisterStartup<My.Cms.Module.Startup>().AddLiquidViews();
});
} |
Okay just tried the following, all from the command line In MyModule folder
MyPart is not a good name as it created a MyPartPart ;) Then In MyApp folder
Then in MyApp.csproj I referenced MyModule
Then In MyApp folder
Then I got the setup screen, selected the Blog recipe and run the setup Then in the Admin, under content definitions MyPart was not yet exposed, so I went to the Features page to enable MyModule, then MyPart was listed under content definitions. Then I added MyPart to the existing Article Type, edited the About article and checked the boolean Finally I went to the About page, MyPart was not rendered because the blog theme for the Article Type in its related Liquid file doesn't fully use the shape system, it renders only some parts explicitly so not new ones. So I went to the Admin > Design > Themes and selected When running the above ocmodulecms command a I also noticed a Hope this will help |
So, if I understand the conventions correctly, dots |
@jtkech Show your app code,
Details:
I assume because 'nothing' has been registered, but 'something', i.e. the module, has been detected, i.e. via Project References. |
Commented out the |
@jtkech Did you try adding that part to the default Content Item? Then in the
I remove the part from the Content Type, and no exception. So, IMO, SOMETHING is blocking. |
Yes, you need at least to call
Yes, and re-tried it with the Agency setup recipe, so that I could add MyPart to the LandingPage type.
It works, I didn't do anything, just used the generated code. MyApp startup
MyModule startup
Is it the same exception saying that it didn't find the YourPart.Edit.cshtml ? Hmm, if so maybe because your App project file and Module project file are not targetting the same TFM. Can you check that your project files are both targetting net6.0? This because in net6.0 razor views are embedded in the same module assembly, before e.g. in net5.0 they were embedded in a separate MyModule.Views.dll. MyApp.csproj
MyModule.csproj
|
Yes. Same exception. If/when that detail changes, I will say so.
TFM? You mean
Let me stop you there. There is nothing to 'check' for the afore mentioned reasons. Now, if there is project template content that is obsolete now... (?) that is a whole other issue / can of worms, now isn't it? Still, was failing before/after the As I've said, if I do not register the module Again, the key seems to be a difference between: services.AddOrchardCms(configure =>
{
// with or without liquid views... does not matter.
configure.RegisterStartup<Elumination.Cms.Module.Startup>().AddLiquidViews();
}); Versus: services.AddOrchardCms(); I am only gaining the benefit of the module |
Take care, in the doc we have the current warning
That's why I used this option for both installing MyApp and MyModule, and then I showed you the exact code I was using. But if you don't want to show us the exact code you are using, I can't help you anymore. But no problem, at least it was very interesting to try to help someone like you ;) |
I am using the project templates; the result, AFAIK, is the same. This is via VS2022, right. There is not the same project template under a VS2019, because the target frameworks have changed circa Kindly, we are 'there', IMO, in terms of zeroing in on possible root causes. Let's see that through. @jtkech So... did you try registering your services.AddOrchardCms(configure =>
{
configure.RegisterStartup<Elumination.Cms.Module.Startup>().AddLiquidViews();
}); Concerning yours versus my Thank you. |
Re:
That's not a bug, per se; that was a decision, IMO, to drop support for target frameworks prior to |
Yes I used the dotnet CLI, just re-tried by installing the templates under VStudio 2022, same generated code, all works fine.
No, this is done automatically when your module startup inherits from StartupBase, but for the fun just tried it, it still works, I just noticed by using a breakpoint that the module startup is more often called. Edited Never tried to install Templates under VStudio, it gave me the opportunity to try it, beautiful, thanks |
Huh, well, I do derive from For grins I put a debug statement in the handler public AssemblyPartHandler(AssemblyPartDetails details)
{
System.Diagnostics.Debug.WriteLine("here");
Details = details;
} |
@jtkech Would you be willing to join a brief mutual shared desktop? In 10-15 minutes maybe 30 on the outside comparing notes, maybe something will become obvious to one or both of us what is the discrepancy here. Thanks... |
The only other variable that we have not discussed is database backing the Cms ... we are assuming |
For grins, tried to stand up a
OOB we have both @sebastienros Can you verify this please. This is a major show stopper. So far is broken under SQLite, postgres. Assuming perhaps @jtkech is using SQL Server (?), but that is unconfirmed at this point. Again, all this is OOB; if there is more in the way of plumbing we need to touch for it to 'just work', that's what we need to know here. Thank you... |
Don't do that, just keep You just need to add in your app .csproj file a ProjectReference to your module, e.g.
|
Okay, I did that much. What else is Also, in either of the views, @model AssemblyPartViewModel
<div class="form-group">
<div class="custom-control custom-checkbox">
<input type="checkbox" class="custom-control-input" asp-for="Show" />
<label class="custom-control-label" asp-for="Show">@T["Show"]</label>
</div>
</div> Or, @model Spike.Cms.Module.Settings.AssemblyPartSettingsViewModel
<div class="form-group">
<div class="w-xl-75">
<label asp-for="MySetting">@T["Setting"]</label>
<input asp-for="MySetting" class="form-control" />
</div>
<span class="hint">@T["The setting."]</span>
</div> If those are the views, I do not see |
@jtkech Furthermore, as I stated before, I do not think the actual code is being run in the module when you do that. Sure there are no exceptions, however, none of the |
Is your module enabled ? |
What does that mean? I do not see it listed among the Features? First, I do not see it listed among Edit: Ah 💡 now I see it. Now code is running. It's a bit awkward OOB between the "The setting" and editing the content item Thanks! |
A Module has msbuild scripts (in .props and .targets files), this ensures that there are executed when building your app, in fact not necessary when you reference it directly, required when a module is referenced indirectly through another project/package. |
Well if your part is in a module, you have to enable the module for the Shapes to be added to the list of available shapes. |
Yes, because at some point the module startup was explicitly registered from the app startup |
Yes, as said in a previous comment
|
All good now !!! |
Well, it's progress at any rate; I'll take me victories when/where I can find them 🎆 🥳 🍾 |
Yes, closed finally. Mini-saga. Satisfied now that I have a better understanding what is connecting where, how, etc. |
Version
Using Orchard Core Cms App, Module, etc, VS2019 project templates,
1.2.2
.Describe the bug
Exception adding custom part to out of the box boilerplate recipe item.
To Reproduce
I added the custom content part to the item type, tried to edit, then I got this.
Expected behavior
First should probably have an Edit view out of the box, or that there was one, the naming convention is misaligned, perhaps. The default I think was,
AssemblyCredentialsPart.Edit.cshtml
, but I'm not certain.Follow on concerns
And perhaps corrolary to this, what is it that we should edit per se, for a custom part? And how does that relay through the model, view model, etc, what sort of bindings are there, what is serialized and persistent if at all, and so forth.
The text was updated successfully, but these errors were encountered: