Replies: 6 comments 1 reply
-
I would not be comfortable making these changes to the core framework unless I understood much more about the scenario. It sounds like these changes are needed in order to support interoperability with MVC - which is not really a primary focus in Oqtane at this point because it is focused on Blazor and the razor component model. You are correct that the framework is using LoadFromStream because LoadFromAssemblyPath locks the DLL files and prevents them from being deleted. When a user chooses to delete a Module from the Admin Dashboard/Module Management area or a TTheme from the Admin Dashboard/Theme Management area it has logic to remove all of the associated resources including DLLs. When the framework was using LoadFromAssemblyPath originally it would fail because the DLLs were locked. This is a problem because it would not fully clean up the resources and when the framework restarts it will locate these DLLs and reinstall them automatically (as expected). |
Beta Was this translation helpful? Give feedback.
-
Hmm... I can get round the reference to Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation by including runtime components in the module package. It's just easier if the version matching is done by the package manager. The call to LoadFromAssemblyPath is harder to finesse. The Location property on the external module really does need to be set. BTW: the reason I thought LoadFromAssemblyPath didn't lock the dll's, is that I was able to move the dlls out of the bin folder while Oqtane was running. File.Move will do the job handily. So as an alternative to using LoadFromStream, would you consider changes to the package installer to move locked dll's to a temporary folder before extracting the replacement from the .nupkg file. The temporary folders can be deleted when oqtane.server is next started. I note that this would still get in the way of the debug.cmd copy of the module .dlls while debug oqtane.server is running. I'd suggest making the LoadFromStream vs LoadFromAssemblyPath a configurable option. A bit hacky though. I suspect that I won't be the last person to need the Assembly.Location property to be set. It's a commonly used item. If we're still outside your comfort zone - perhaps we need to start a conversation about how to ensure that projects that fork/branch the codebase at release points can ensure that they can upgrade at periodic intervals to keep in sync with the releases from the main branch. Maintaining an individual version of any framework is is a pain... and ensuring production customers don't get trapped in a non-upgradable cul-de-sac seems important. Thoughts? PS. Regarding support of legacy MVC - I'm reminded that the reason that Windows 3.1 beat out OS2 was because it allowed customers to continue to use their legacy DOS programs while they transitioned to the new OS. [I'm old enough to remember, though the details are getting pretty fuzzy these days]. |
Beta Was this translation helpful? Give feedback.
-
Thank you for the more detailed explanation. As I mentioned above, the change was made previously from using LoadFromAssemblyPath to LoadFromStream to eliminate the lock on the DLLs so that the framework would be able to delete DLLs at run-time as part of module or theme Uninstall. Note that Uninstall is the only scenario that needed this behavior. In regards to the opposite scenario - module or theme Install - even though new versions of DLLs can be copied into the /bin to overwrite existing DLLs, Oqtane will not automatically recognize these changes. It will continue to use the bits that are already loaded into the app domain. This is because of the way .NET Core deals with the default app domain ( and based on my experience attempting to use custom app domains became much too complicated and flaky in terms of app behavior ). As a result, Oqtane forces an app restart on the server when a Module or Theme is installed through the UI so that the app domain is unloaded and the startup logic can execute to reload the assemblies ( this is obviously not the case when developing external modules and using the debug.cmd - in which case the developer needs to restart Oqtane manually to reload the assemblies ). So getting back to your suggestion, if it was possible during Uninstall to either rename the DLLs or move them to a different folder, then during startup the framework could clean them up and they would not be reinstalled. This would allow a transition back to LoadFromAssemblyPath. However we would also need to ensure it does not affect Installation - ie. preventing the installer from extracting DLLs into the /bin. Depending on the outcome, we could evaluate if the additional complexity is worth it... as I am still trying to determine if this is in fact an edge case since nobody has ever raised it previously in the past 18 months. |
Beta Was this translation helpful? Give feedback.
-
@tfindlow one other thing I am wondering is why you could not simply change your ConfigureServices() method to use:
This will get the run-time location of the /bin folder where your DLLs reside - which seems to be what you are trying to accomplish? |
Beta Was this translation helpful? Give feedback.
-
It's not my code that needs a value in Location. The Assembly.Location is referenced in the ASP.Net core libraries when RuntimeCompilation is turned on - and an exception is thrown because the value is an empty string. I only need RuntimeCompilation to allow ASP.Net to find MVC views in my external module (to support reporting using FastReports). If I could figure out another way to get ASP.Net to find the MVC view I'd be more than happy to use it. It does appear that there is some embedded mechanism to handle "application parts" in MVC - and that this mechanism works across dll boundaries somehow, but as usual there's no documentation... The runtime compilation technique is the only working mechanism I can find described on the web. |
Beta Was this translation helpful? Give feedback.
-
just a side note on Stimulsoft they have released Blazor Components that are native and support Server and WASM apps. https://www.stimulsoft.com/en/products/reports-blazor |
Beta Was this translation helpful? Give feedback.
-
I have been working to embed reports in an external module - specifically FastReport.OpenSource.Web. A prepared FastReport.Web.WebReport object is passed to a MVC view, and the report object renders html directly into the view. The same technique is used by Stimulsoft. Since this is non-blazor html, the view has to be displayed in an iframe, or to another tab in the browser.
For this to work in Oqtane, Asp.Net must be able to find the view in the external module assembly. This is a known problem and has been solved in other projects using a combination of techniques documented on the web. This involves creation of an EmbeddedFileProvider and the addition of MVC Razor Runtime Compilation.
The changes required of Oqtane.Server v1.0.4 are as follows:
The second change is required because the runtime compilation fails if the assembly.Location is empty (which it is if we use LoadFromStream).
A note in the code (OqtaneServiceCollectionExtensions.cs) indicates that the LoadFromStream was selected to ensure that the assembly dll is not locked. However, it does not appear that LoadFromAssemblyPath locks the module dll.
The LoadFromStream explicitly loads symbols. It seems LoadFromAssemblyPath will implicitly load symbols, since I can use the debugger to attach to the iiexpress process running the debug Oqtane.Server.
So the question is: Is there any reason these 2 changes can't be applied to the standard release?
The setup in the external module (tfindlow6929.Fred) Server is as follows:
Beta Was this translation helpful? Give feedback.
All reactions