Closed mwpowellhtx closed 2 years ago
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.
Literally this is more or less what happened out of the box. I have not changed it. I added a couple more model elements in there anticipating integration of Assembly
and derivative bits was all.
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.
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 Assembly
DI to happen correctly, at least on the surface. Not sure what is happening with Edit however.
Does it run the Startup.cs file at all?
services.AddOrchardCms(config =>
{
config.RegisterStartup<Path.To.Cms.Module.Startup>();
});
This part here, not sure it is necessary.
Does it run the Startup.cs file at all?
That is evaluated, yes.
This part here, not sure it is necessary.
IIRC was required in order for the part to appear among the other assets i.e.
Which we can add it to a content type no problem. But when we try to edit said type, Exception
.
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. Of course, this won't throw any exceptions because nothing prevents you from doing it.
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.
All of this won't work. because you are registering it at the app level while it needs to be registered at each tenant.
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 Sub tenant : domain2.com
Each of these tenants will have their own database configuration and will be an entire new Orchard Core instance. So domain.com/admin will be different than domain2.com/admin.
Right, I get that, which is just another web app. i.e. www.ourdomain.com
, versus shop.ourdomain.com
, or blog.ourdomain.com
each of which routed to a different app.
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 AssemblyCredentialsPart.Edit.cshtml
be rather named AssemblyCredentialsPart_Edit.cshtml
i.e. by convention? If so, easy enough to fix that, however, y'all probably want to patch the template as well, because AssemblyCredentialsPart.Edit.cshtml
is what we got out of the box. Thank you...
At least...
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? https://github.com/Lombiq/Orchard-Training-Demo-Module https://github.com/Lombiq/Orchard-Training-Demo-Module/blob/dev/Startup.cs#L80
Reviewing that, thank you.
Can you check Lombiq's tutorial that explains how to create custom Parts and their view...
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 Default
tenant with an empty url prefix by default but you can setup additional ones. So yes a tenant is like an isolated app (notice that we have helpers allowing tenant1 to use services of tenant2) which is composed of modules which are composed of features (at least one main feature per module) that can be enabled / disabled per tenant. When setting up a tenant you can define the set of module features to be used through a recipe.
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 OrchardCore.Module.Targets
package or Theme.targets
for a theme.
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 ConfigureServices()
is called, when the tenant pipeline is building the module startup Configure()
is called, notice that we have different way to control the order of startup calls through startup properties and features dependencies in the module manifest files.
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.
config.RegisterStartup<Path.To.Cms.Module.Startup>();
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 ConfigureServices()
and Configure()
helpers that act on an OrchardCoreBuilder
, this builder being returned e.g. by AddOrchardCms()
services.AddOrchardCms()
.ConfigureServices(s =>
{
s.AddSomeServicesAtTenantLevel();
},
order: 100) // <= here an optional order property
.AddSetupFeatures("OrchardCore.AutoSetup");
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 .
and -
characters, they use _
and __
, so the SomePart_Edit
template is related to the SomePart.Edit.cshtml
file.
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 ConfigureServices
route versus RegisterStartup
(?), i.e. if I can summarize, this does that, that does this, and the two meet in the middle.... Or why not just 'register'? Or for that matter, adding the reference and allowing OC to discover those module startups by convention transparently, if that's a thing; i.e. transparently discover them as 'plugins' (?). At any rate, I'll pick up with the 1.3.0
OC CMS module as my starting point and compare notes as necessary and see how far we get with that. Thanks for the response. 🍻
@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?
So to be clear, I do not see the module available in the site admin Configuration for it to be activated at all. So there still needs to be glue there, correct? Is the extension method literally called AddSomeServicesAtTenantLevel
? I'm not clear what that means, per se.
Again, for the part to be visible, for starters, in the Content Parts, I needed to have registered its Startup
, which stands to reason. I do not see any other way to connect those dots. What am I missing there?
I add the part in the place that I want it in the Content Item definition, that is fine enough. But when we go to edit that item, that is when we get exceptions.
Exception: Shape type 'AssemblyPart_Edit' not found
OrchardCore.DisplayManagement.Implementation.DefaultHtmlDisplay.ExecuteAsync(DisplayContext context)
OrchardCore.DisplayManagement.Implementation.DefaultHtmlDisplay.ExecuteAsync(DisplayContext context)
CallSite.Target(Closure , CallSite , object )
AspNetCoreGeneratedDocument.Views_ContentPart_Edit.ExecuteAsync()
Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderPageCoreAsync(IRazorPage page, ViewContext context)
Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderPageAsync(IRazorPage page, ViewContext context, bool invokeViewStarts)
Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderAsync(ViewContext context)
Microsoft.AspNetCore.Mvc.ViewFeatures.HtmlHelper.RenderPartialCoreAsync(string partialViewName, object model, ViewDataDictionary viewData, TextWriter writer)
Microsoft.AspNetCore.Mvc.ViewFeatures.HtmlHelper.PartialAsync(string partialViewName, object model, ViewDataDictionary viewData)
OrchardCore.DisplayManagement.Implementation.DefaultHtmlDisplay.<ProcessAsync>g__Awaited|11_0(Task<IHtmlContent> task)
OrchardCore.DisplayManagement.Implementation.DefaultHtmlDisplay.ExecuteAsync(DisplayContext context)
OrchardCore.DisplayManagement.Implementation.DefaultHtmlDisplay.ExecuteAsync(DisplayContext context)
OrchardCore.DisplayManagement.Zones.ZoneShapes.ContentZone(IDisplayHelper DisplayAsync, object Shape, IShapeFactory ShapeFactory)
OrchardCore.DisplayManagement.Implementation.DefaultHtmlDisplay.<ProcessAsync>g__Awaited|11_0(Task<IHtmlContent> task)
OrchardCore.DisplayManagement.Implementation.DefaultHtmlDisplay.ExecuteAsync(DisplayContext context)
OrchardCore.DisplayManagement.Implementation.DefaultHtmlDisplay.ExecuteAsync(DisplayContext context)
CallSite.Target(Closure , CallSite , object )
AspNetCoreGeneratedDocument.Views_Content_Edit.ExecuteAsync()
Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderPageCoreAsync(IRazorPage page, ViewContext context)
Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderPageAsync(IRazorPage page, ViewContext context, bool invokeViewStarts)
Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderAsync(ViewContext context)
Microsoft.AspNetCore.Mvc.ViewFeatures.HtmlHelper.RenderPartialCoreAsync(string partialViewName, object model, ViewDataDictionary viewData, TextWriter writer)
Microsoft.AspNetCore.Mvc.ViewFeatures.HtmlHelper.PartialAsync(string partialViewName, object model, ViewDataDictionary viewData)
OrchardCore.DisplayManagement.Implementation.DefaultHtmlDisplay.<ProcessAsync>g__Awaited|11_0(Task<IHtmlContent> task)
OrchardCore.DisplayManagement.Implementation.DefaultHtmlDisplay.ExecuteAsync(DisplayContext context)
OrchardCore.DisplayManagement.Implementation.DefaultHtmlDisplay.ExecuteAsync(DisplayContext context)
CallSite.Target(Closure , CallSite , object )
System.Dynamic.UpdateDelegates.UpdateAndExecute1<T0, TRet>(CallSite site, T0 arg0)
AspNetCoreGeneratedDocument.Views_Admin_Edit+<>c__DisplayClass14_0+<<ExecuteAsync>b__1>d.MoveNext()
Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperExecutionContext.GetChildContentAsync(bool useCachedResult, HtmlEncoder encoder)
Microsoft.AspNetCore.Mvc.TagHelpers.RenderAtEndOfFormTagHelper.ProcessAsync(TagHelperContext context, TagHelperOutput output)
Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperRunner.<RunAsync>g__Awaited|0_0(Task task, TagHelperExecutionContext executionContext, int i, int count)
AspNetCoreGeneratedDocument.Views_Admin_Edit.ExecuteAsync()
Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderPageCoreAsync(IRazorPage page, ViewContext context)
Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderPageAsync(IRazorPage page, ViewContext context, bool invokeViewStarts)
Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderAsync(ViewContext context)
Microsoft.AspNetCore.Mvc.ViewFeatures.ViewExecutor.ExecuteAsync(ViewContext viewContext, string contentType, Nullable<int> statusCode)
Microsoft.AspNetCore.Mvc.ViewFeatures.ViewExecutor.ExecuteAsync(ViewContext viewContext, string contentType, Nullable<int> statusCode)
Microsoft.AspNetCore.Mvc.ViewFeatures.ViewExecutor.ExecuteAsync(ActionContext actionContext, IView view, ViewDataDictionary viewData, ITempDataDictionary tempData, string contentType, Nullable<int> statusCode)
Microsoft.AspNetCore.Mvc.ViewFeatures.ViewResultExecutor.ExecuteAsync(ActionContext context, ViewResult result)
Microsoft.AspNetCore.Mvc.ViewResult.ExecuteResultAsync(ActionContext context)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeResultAsync>g__Logged|22_0(ResourceInvoker invoker, IActionResult result)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResultFilterAsync>g__Awaited|30_0<TFilter, TFilterAsync>(ResourceInvoker invoker, Task lastTask, State next, Scope scope, object state, bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResultExecutedContextSealed context)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.ResultNext<TFilter, TFilterAsync>(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeResultFilters>g__Awaited|28_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, object state, bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|25_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, object state, bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|20_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, object state, bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Logged|17_1(ResourceInvoker invoker)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Logged|17_1(ResourceInvoker invoker)
Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
SixLabors.ImageSharp.Web.Middleware.ImageSharpMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
OrchardCore.Liquid.ScriptsMiddleware.Invoke(HttpContext httpContext)
Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
OrchardCore.Diagnostics.DiagnosticsStartupFilter+<>c__DisplayClass3_0+<<Configure>b__1>d.MoveNext()
Microsoft.AspNetCore.Diagnostics.StatusCodePagesMiddleware.Invoke(HttpContext context)
OrchardCore.ContentPreview.PreviewStartupFilter+<>c+<<Configure>b__1_1>d.MoveNext()
OrchardCore.Modules.ModularTenantRouterMiddleware.Invoke(HttpContext httpContext)
OrchardCore.Logging.SerilogTenantNameLoggingMiddleware.Invoke(HttpContext context)
OrchardCore.Modules.ModularTenantContainerMiddleware+<>c__DisplayClass4_0+<<Invoke>b__0>d.MoveNext()
OrchardCore.Environment.Shell.Scope.ShellScope.UsingAsync(Func<ShellScope, Task> execute, bool activateShell)
OrchardCore.Environment.Shell.Scope.ShellScope.UsingAsync(Func<ShellScope, Task> execute, bool activateShell)
OrchardCore.Environment.Shell.Scope.ShellScope.UsingAsync(Func<ShellScope, Task> execute, bool activateShell)
OrchardCore.Environment.Shell.Scope.ShellScope.UsingAsync(Func<ShellScope, Task> execute, bool activateShell)
OrchardCore.Modules.ModularTenantContainerMiddleware.Invoke(HttpContext httpContext)
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
Again, this is all out of the box. Nothing spectacular there.
This is common error when
OrchardCore.Module.Targets
On your module project ORAnother observation, when the app is closing out, I get the following error in the console. Only apparently when I am registering the Startup
.
\\Path\To\src\My.Cms.Web\bin\Debug\net6.0\My.Cms.Web.exe (process 30388) exited with code -1.
To automatically close the console when debugging stops, enable Tools->Options->Debugging->Automatically close the console when debugging stops.
This is common error when
- you do not have reference of
OrchardCore.Module.Targets
On your module project OR
I do not see how that is possible. I started the project literally using the OC Cms Module project template.
- You have not used dotnet command line to create occmsmodule or you have manually changed to content OR
- Your shape is in main app and missing in publishes folder
Don't know what you mean shape. Literally this is OOB stuff. Nothing fancy there, using the default Show
etc bits. So you're saying that the template OOB is broken? Then there needs to be more detailed instructions what to connect.
Now, I do not intend for that to be the destination, of course. I am just trying to spin it up and get something on its feet that I can compare notes against.
Again by shape isn't that the point of standing this up in its own module? The module knows the model, view model, i.e. shape, if I understand you correctly. The only thing the app needs to do is be connected with the feature, module, etc, correct?
Edit: Also, in this particular case, I simply want to display some assembly information for Copyright and credentialing purposes. Not unlike some sites do. So the app really has no knowledge, nor should it, on that issue, the model, the view model, etc. Rather, that is the purpose of the views provided by the module.
I am trying to inject System.Reflection.Assembly
bits, of course. That plumbing seems to be just fine, in and of itself. But whatever is asking for an editor, does not like that, and I do not know what. I wrap the Assembly
instance in a Details class, and that I connect with the handler, which in turn feeds that instance to the Content Part on Initialization
. That appears to be working. Would someone be able to review this further without necessarily going public? Thanks...
Have you looked at @jtkech suggestions before saying that it's a OOB content part? We have plenty of those working in the source code right now so there is maybe something with the DI that you are doing wrong as we suggested.
Yes. I am not finding anything that different from the examples. I'm not sure what the exception is to be honest. Nothing wrong with the DI as I said, the plumbing connects the dots I would expect, including and through Initialization. Then I get the exception.
How about this, just try to start a module OOB and see if it stands up "as-is". It is looking for an edit view (?). But, apparently, there "is one" OOB. So how is it this is not hooking up properly? What I need to see is from the app perspective for comparison.
Hmm, I see above that you defined AssemblyCredentialsPart.Edit.cshtml
so normally it should work.
Can you share on github a simple app referencing your module just to repro, so that we could try it and I hope fix it.
Hmm, I see above that you defined
AssemblyCredentialsPart.Edit.cshtml
so normally it should work.Can you share on github a simple app referencing your module just to repro, so that we could try it and I hope fix it.
Again TO BE CLEAR, I did not define ANYTHING. Okay, I wired up some details which connected to the Assembly
appropriately, as expected. But OTHER THAN THAT, it was all boilerplate OOB. Like I said, start from the OC Cms Module project template, and let's compare some notes, please.
@jtkech What I need to see is how the PersonPart
module is integrated, by an OC Cms App, presumably, ostensibly. Is there that example as well? Comparing notes with that, how is the Startup
registered, etc.
Okay, I would need to retry our OC Cms Project Templates, I will try to do it asap ;)
To integrate a given Module project, your OC Cms app should reference it as a project, then if your module references the Module.Targets package it will be automatically recognized as a module, then as soon as your module is enabled in the current tenant (here the default one), its startup will be used when building the tenant container.
...then if your module references the Module.Targets package...
Starting from the OC Cms Module does all that for you, I think, appropriate targets, etc. I showed that the part does actually appear to the admin
screens above. So that much "just works".
...your OC Cms app should reference it as a project...
Yep; I did do the reference; then AFAIK I register the Startup
. That was it (?). If there is other glue I need to provide, that's what I need to know. But which also beggars a string of other questions, but let's see that first. 👍 Thanks!
From the App perspective, I tried this, with and without .AddLiquidViews()
, exception in either case.
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
dotnet new ocmodulecms --AddPart true --PartName MyPart --orchard-version 1.3.0
MyPart is not a good name as it created a MyPartPart ;)
Then In MyApp folder
dotnet new occms --orchard-version 1.3.0
Then in MyApp.csproj I referenced MyModule
<ProjectReference Include="..\MyModule\MyModule.csproj" PrivateAssets="none" />
Then In MyApp folder
dotnet build
bin/debug/net6.0/MyApp.exe
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 Show
field.
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 The Default Theme
, then MyPart was rendered.
When running the above ocmodulecms command a MyPartPart.Edit.cshtml
was created for editing the part model only having a bool Show
property (not a ContentField here), and a MyPartPart.liquid
for rendering on the front end, here just to display the contentItemId if the Show field is true.
I also noticed a MyPartPart_Summary.liquid
normally used when rendered in a list, but I think that the name is wrong, should not use an underscore I think, underscores are used internally by the code to manage template names, normally the related files should use -
and .
chars instead.
Hope this will help
So, if I understand the conventions correctly, dots .
for cshtml
, underscores _
for liquid
, which 'is', but I could be wrong there. Which is what lands there OOB. No need to go to any of the admin, UI, etc. They just 'are' OOB. But there is an exception, maybe details, etc, need to be serializable? I'm not sure. How would I wire up a details, or a System.Reflection.Assembly
, or AssemblyName
, or do I need to mine and extract for read-only bits that I am interested to convey via the views and so forth? It is sounding to me more like that is the case.
@jtkech Show your app code, Startup
, etc, please. Did you register anything there? I took out the registration for now and am receiving this exception during the app.UseOrchardCore(...)
call:
System.InvalidOperationException: 'No service for type 'OrchardCore.Modules.IApplicationContext' has been registered.'
Details:
System.InvalidOperationException
HResult=0x80131509
Message=No service for type 'OrchardCore.Modules.IApplicationContext' has been registered.
Source=Microsoft.Extensions.DependencyInjection.Abstractions
StackTrace:
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
at Microsoft.AspNetCore.Builder.ApplicationBuilderExtensions.UseOrchardCore(IApplicationBuilder app, Action`1 configure)
at Emporium.Cms.Web.Startup.Configure(IApplicationBuilder app, IHostEnvironment env) in L:\Source\Emporium\Web-Master-Net6\src\Emporium.Cms.Web\Startup.cs:line 27
at System.RuntimeMethodHandle.InvokeMethod(Object target, Span`1& arguments, Signature sig, Boolean constructor, Boolean wrapExceptions)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at Microsoft.AspNetCore.Hosting.ConfigureBuilder.Invoke(Object instance, IApplicationBuilder builder)
at Microsoft.AspNetCore.Hosting.ConfigureBuilder.<>c__DisplayClass4_0.<Build>b__0(IApplicationBuilder builder)
at Microsoft.AspNetCore.Hosting.GenericWebHostBuilder.<>c__DisplayClass15_0.<UseStartup>b__1(IApplicationBuilder app)
at Microsoft.AspNetCore.HostFilteringStartupFilter.<>c__DisplayClass0_0.<Configure>b__0(IApplicationBuilder app)
at Microsoft.WebTools.BrowserLink.Net.HostingStartup.<>c__DisplayClass1_0.<Configure>b__0(IApplicationBuilder app)
at Microsoft.AspNetCore.Watch.BrowserRefresh.HostingStartup.<>c__DisplayClass1_0.<Configure>b__0(IApplicationBuilder app)
at Microsoft.AspNetCore.Hosting.GenericWebHostService.<StartAsync>d__37.MoveNext()
I assume because 'nothing' has been registered, but 'something', i.e. the module, has been detected, i.e. via Project References.
Commented out the Assembly
details stuff and retried. Still getting an exception!!!!!
@jtkech Did you try adding that part to the default Content Item? Then in the admin
UI, try to edit that Content Item. Tell me what you get. Show your OC Cms App Startup
, please. Thank you...
LandingPage
in the Content Types, i.e. https://localhost:5001/Admin/ContentTypes/Edit/LandingPage
LandingPage
instance in the Content Items, visiting that example, trying to Edit, whatever, throws the exceptionI remove the part from the Content Type, and no exception.
So, IMO, SOMETHING is blocking.
I took out the registration for now and am receiving this exception during the app.UseOrchardCore(...) call: 'No service for type 'OrchardCore.Modules.IApplicationContext' I assume because 'nothing' has been registered
Yes, you need at least to call AddOrchardCms()
that registers IApplicationContext
.
Did you try adding that part to the default Content Item? Then in the admin UI, try to edit that Content Item.
Yes, and re-tried it with the Agency setup recipe, so that I could add MyPart to the LandingPage type.
Tell me what you get. Show your OC Cms App Startup, please. Thank you...
It works, I didn't do anything, just used the generated code.
MyApp startup
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddOrchardCms();
}
public void Configure(IApplicationBuilder app, IHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseStaticFiles();
app.UseOrchardCore();
}
}
MyModule startup
public class Startup : StartupBase
{
public override void ConfigureServices(IServiceCollection services)
{
services.Configure<TemplateOptions>(o =>
{
o.MemberAccessStrategy.Register<MyPartPartViewModel>();
});
services.AddContentPart<MyPartPart>()
.UseDisplayDriver<MyPartPartDisplayDriver>()
.AddHandler<MyPartPartHandler>();
services.AddScoped<IContentTypePartDefinitionDisplayDriver, MyPartPartSettingsDisplayDriver>();
services.AddScoped<IDataMigration, Migrations>();
}
public override void Configure(IApplicationBuilder builder, IEndpointRouteBuilder routes, IServiceProvider serviceProvider)
{
routes.MapAreaControllerRoute(
name: "Home",
areaName: "MyModule",
pattern: "Home/Index",
defaults: new { controller = "Home", action = "Index" }
);
}
}
Then in the LandingPage instance in the Content Items, visiting that example, trying to Edit, whatever, throws the exception
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
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
<RazorRuntimeCompilation>false</RazorRuntimeCompilation>
</PropertyGroup>
<ItemGroup>
<Folder Include="wwwroot\" />
<Folder Include="Localization\" />
</ItemGroup>
<!-- Watcher include and excludes -->
<ItemGroup>
<Watch Include="**\*.cs" Exclude="Recipes\**;Assets\**;node_modules\**\*;**\*.js.map;obj\**\*;bin\**\*" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="1.3.0"
Condition="'$(RazorRuntimeCompilation)' == 'true'" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="OrchardCore.Logging.NLog" Version="1.3.0" />
<PackageReference Include="OrchardCore.Application.Cms.Targets" Version="1.3.0" />
<ProjectReference Include="..\MyModule\MyModule.csproj" PrivateAssets="none" />
</ItemGroup>
</Project>
MyModule.csproj
<Project Sdk="Microsoft.NET.Sdk.Razor">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<AddRazorSupportForMvc>true</AddRazorSupportForMvc>
</PropertyGroup>
<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="OrchardCore.Module.Targets" Version="1.3.0" />
<PackageReference Include="OrchardCore.ContentManagement" Version="1.3.0" />
<PackageReference Include="OrchardCore.ContentTypes.Abstractions" Version="1.3.0" />
<PackageReference Include="OrchardCore.DisplayManagement" Version="1.3.0" />
</ItemGroup>
</Project>
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.