D
D
Dmitry Petrov2017-04-10 12:00:00
.NET
Dmitry Petrov, 2017-04-10 12:00:00

How to get list of types in open ClassLibrary at DesignTime in VisualStudio?

Perhaps the question is worded a little chaotically.
I use a slightly extended custom MvcWebPageRazorHost, the question arose of how to automatically import namespaces (NamespacesImport) into WebPageRazorHost (in order not to write a rather large list in web.config, and for a number of other reasons). This should work at runtime and designtime.
The structure is approximately the following: there is a Core project (let's call it that).
There are two classes inside:

namespace Core
{
    public class CustomWebRazorHostFactory : MvcWebRazorHostFactory
    {
        public override WebPageRazorHost CreateHost(string virtualPath, string physicalPath)
        {
            return CustomWebPageRazorHost.CreateFromAnother(base.CreateHost(virtualPath, physicalPath));
        }
    }

    class CustomWebPageRazorHost : MvcWebPageRazorHost
    {
        public static CustomWebPageRazorHost CreateFromAnother(WebPageRazorHost host)
        {
            var newHost = new CustomWebPageRazorHost(host.VirtualPath, host.PhysicalPath);

            newHost.DefaultBaseClass = typeof(CustomWebViewPage<>).FullName.Replace("`1", "");
            newHost.DefaultClassName = host.DefaultClassName;
            newHost.DefaultDebugCompilation = host.DefaultDebugCompilation;
            newHost.DefaultPageBaseClass = typeof(CustomWebViewPage<>).FullName.Replace("`1", "");
            newHost.DesignTimeMode = host.DesignTimeMode;
            newHost.EnableInstrumentation = host.EnableInstrumentation;
            newHost.GeneratedClassContext = host.GeneratedClassContext;
            newHost.InstrumentedSourceFilePath = host.InstrumentedSourceFilePath;
            newHost.IsIndentingWithTabs = host.IsIndentingWithTabs;
            newHost.TabSize = host.TabSize;

            foreach (string current in host.NamespaceImports) newHost.NamespaceImports.Add(current);

            return newHost;
        }

        protected CustomWebPageRazorHost(string s1, string s2) : base(s1, s2)
        {
            try
            {
                this.NamespaceImports.Add("System.Web.Helpers");
                this.NamespaceImports.Add("System.Web.Mvc");
                this.NamespaceImports.Add("System.Web.Mvc.Html");
                this.NamespaceImports.Add("System.Web.Routing");
                this.NamespaceImports.Add("System.Collections");

                var namespaces = Utils.ReflectionHelper.GetEngineNamespaces();
                foreach (var _namespace in namespaces)
                {
                    this.NamespaceImports.Add(_namespace);
                }

            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.ToString());
            }
        }
    }
}

There is a Web project (let's call it that) that connects Core and registers "host factoryType" in web.config as follows:
<host factoryType="Core.CustomWebRazorHostFactory, Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=..." />

All the magic happens inside GetEngineNamespaces. To put it simply, we get a certain list of assemblies (Assembly), take certain types from there (GetExportedTypes plus a bit of filtering) and get the desired namespaces and shove it into this.NamespaceImports.
There are no problems with runtime. All the necessary assemblies are already loaded into the domain memory and it is enough just to iterate them and get the types.
There was a small design-time glitch while working with a view in a Web project in Visual Studio.
Firstly, I had to sign the Core library with a strong name and register it in the GAC, otherwise the studio does not see Core at designtime and, accordingly, does not see the CustomWebRazorHostFactory type.
Secondly, at designtime, only the Core assembly is in the AppDomain in VisualStudio. I'll try to explain.
If you start the studio and open the whole solution (solution), then open another copy of the studio and pick up the first one with the debugger ("Attach to process"), you can track what happens inside GetEngineNamespaces at the moment the view is opened in the studio editor. Well, I'm following. The AppDomain contains about 500 downloaded assemblies, that's all - assemblies of the studio itself, extensions, third-party components, and so on. Plus, there is a loaded Core assembly, tk. GetEngineNamespaces is called within it. BUT! In addition to Core, there are a number of types within the Web whose namespaces I need to reflect in NamespacesImport. But the Web assembly is not in the AppDomain of the studio, because it is an assembly open in Solution.
So, the question of the day - how can you reach some context inside the studio in order to pull out the same types and namespaces that, relatively speaking, Intellisense sees inside the Web?
PS If you have three projects, Core, WebAdditional and Web, connect WebAdditional and Core inside the Web, then in the designtime of the view in the Web there will again be only Core, but I need to see WebAdditional as well.

Answer the question

In order to leave comments, you need to log in

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question