Plugin Subdirectory in Azure Deployment

I use MEF to expand my web application and I use the following folder structure

  > bin
   > extensions
     > Plugin1
     > Plugin2
     > Plugin3

To achieve this automatically, the output paths of plug-in projects are installed in these directories. My application works with and without the azure line. My problem is that it seems impossible to include the extensions subdirectory automatically in the azure package for deployment.

I also tried to install build dependencies, without success.

Is there another way?

+4
source share
1 answer

Well,

I struggled with the bin folder. The problem (if we can say “problem”) is that the packaging process simply packs what it “copies to the directory” set to “copy if new or always” only for the web application project (web role). The presence of other assemblies in the BIN that do not explicitly reference the web application will not be deployed.

In my case, when I have pretty “static” links, I just pack them in a ZIP, put them in a BLOB container, and then use the Azure Bootstrapper to load, extract and put these links in the BIN folder. However, since I do not know the actual location of the BIN folder in the startup task, I use helper shells for the bootloader to do the trick.

You will need to get a list of local sites that can be done with:

public IEnumerable<string> WebSiteDirectories { get { string roleRootDir = Environment.GetEnvironmentVariable("RdRoleRoot"); string appRootDir = (RoleEnvironment.IsEmulated) ? Path.GetDirectoryName(AppDomain.CurrentDomain.BaseDirectory) : roleRootDir; XDocument roleModelDoc = XDocument.Load(Path.Combine(roleRootDir, "RoleModel.xml")); var siteElements = roleModelDoc.Root.Element(_roleModelNs + "Sites").Elements(_roleModelNs + "Site"); return from siteElement in siteElements where siteElement.Attribute("name") != null && siteElement.Attribute("name").Value == "Web" && siteElement.Attribute("physicalDirectory") != null select Path.Combine(appRootDir, siteElement.Attribute("physicalDirectory").Value); } } 

If the variable _roleModelNs is defined as follows:

 private readonly XNamespace _roleModelNs = "http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition"; 

Next, you'll need something similar to this method:

  public void GetRequiredAssemblies(string pathToWebBinfolder) { string args = string.Join("", @"-get https://your_account.blob.core.windows.net/path/to/plugin.zip -lr $lr(temp) -unzip """, pathToWebBinfolder, @""" -block"); this._bRunner.RunBootstrapper(args); } 

And RunBootstrapper has the following signature:

 public bool RunBootstrapper (string args) { bool result = false; ProcessStartInfo psi = new ProcessStartInfo(); psi.FileName = this._bootstrapperPath; psi.Arguments = args; Trace.WriteLine("AS: Calling " + psi.FileName + " " + psi.Arguments + " ..."); psi.CreateNoWindow = true; psi.ErrorDialog = false; psi.UseShellExecute = false; psi.WindowStyle = ProcessWindowStyle.Hidden; psi.RedirectStandardOutput = true; psi.RedirectStandardInput = false; psi.RedirectStandardError = true; // run elevated // psi.Verb = "runas"; try { // Start the process with the info we specified. // Call WaitForExit and then the using statement will close. using (Process exeProcess = Process.Start(psi)) { exeProcess.PriorityClass = ProcessPriorityClass.High; string outString = string.Empty; // use ansynchronous reading for at least one of the streams // to avoid deadlock exeProcess.OutputDataReceived += (s, e) => { outString += e.Data; }; exeProcess.BeginOutputReadLine(); // now read the StandardError stream to the end // this will cause our main thread to wait for the // stream to close string errString = exeProcess.StandardError.ReadToEnd(); Trace.WriteLine("Process out string: " + outString); Trace.TraceError("Process error string: " + errString); result = true; } } catch (Exception e) { Trace.TraceError("AS: " + e.Message + e.StackTrace); result = false; } return result; } 

Of course, in your case, you may need something more complicated, in which you first try to extract all the plugins (if each plugin is in its own ZIP) through the code, and then execute GetRequiredAssemblies several times for each plugin. And this code can be executed in the RoleEntryPoint OnStart method.

And also, if you plan more dynamically, you can also override the Run () method of your RoleEntryPoint subclass and, for example, check for new plugins every minute.

Hope this helps!

EDIT

And how can you connect plugins. Well, you can manually load your plugins, or you can develop a small custom BuildTask to automatically load the plugin during assembly.

+1
source

Source: https://habr.com/ru/post/1386201/


All Articles