using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.CSharp;
using System.CodeDom.Compiler;
using System.IO;
using System.Reflection;
using System.Activities;
using System.Xaml;
using System.Activities.XamlIntegration;
using System.Diagnostics;
using System.Windows.Threading;
using Selen.WorkflowDesigner.Storage.Contracts;
namespace Selen.ActivityWorkflowType
{
public class ActivityStorageAdapter : IStorageAdapter
{
private string compiledFileName = ActivityPaths.DestFileName;
private string sourceFileName = ActivityPaths.FileName;
private Dispatcher dispatcher = Dispatcher.CurrentDispatcher;
public ActivityStorageAdapter()
{
AppDomain.CurrentDomain.AssemblyResolve += (sender, e) => (from item in Directory.EnumerateFiles(compiledFileName) where AssemblyName.GetAssemblyName(item).FullName == e.Name select Assembly.LoadFrom(item)).FirstOrDefault();
}
public IEnumerable<IWorkflowDescription> GetAllWorkflowDescriptions()
{
var lst = new List<WorkflowDescription>();
foreach (var item in Directory.GetFiles(sourceFileName, "*.dll"))
{
var fileName = Path.GetTempFileName();
File.Copy(item, fileName, true);
var asm = Assembly.LoadFrom(fileName);
var toAdd = asm.GetType("DynamicActivities.CompiledActivity", false);
if (toAdd == null || !typeof (ICompiledActivity).IsAssignableFrom(toAdd)) continue;
var instance = (ICompiledActivity)Activator.CreateInstance(toAdd);
lst.Add(new WorkflowDescription(instance.ActivityName) { Description = instance.Description, WorkflowName = instance.ActivityName });
}
return lst;
}
public IDesignerModel CreateNewDesignerModel()
{
return new DesignerModel(new ActivityBuilder() {Name = "CustomActivities.Activity1"}, new ActivityEntity());
}
public bool CanCreateNewDesignerModel
{
get
{
return true;
}
}
public IDesignerModel GetDesignerModel(object key)
{
var file = Path.Combine(sourceFileName, string.Format("{0}.dll", key));
if (!File.Exists(file))
{
return null;
}
var fileName = Path.GetTempFileName();
File.Copy(file, fileName, true);
var asm = Assembly.LoadFrom(fileName);
var type = asm.GetType("DynamicActivities.CompiledActivity", false);
if (type != null && typeof(ICompiledActivity).IsAssignableFrom(type))
{
var instance = (ICompiledActivity)Activator.CreateInstance(type);
object workflow = null;
this.dispatcher.Invoke(() =>
{
try
{
workflow = XamlServices.Load(ActivityXamlServices.CreateBuilderReader(new XamlXmlReader(new StringReader(instance.XAML))));
}
catch
{
workflow = null;
}
});
if (workflow == null)
{
throw new LoadWorkflowException() { XAMLDefinition = instance.XAML, DesignerModel = new DesignerModel(null, new ActivityEntity() { Description = instance.Description }) };
}
return new DesignerModel(workflow, new ActivityEntity() { Description = instance.Description }).ApplyKey();
}
return null;
}
public bool SaveDesignerModel(IDesignerModel designerModel)
{
var model = (DesignerModel)designerModel;
var activityName = ((ActivityBuilder)model.RootActivity).Name;
if (string.IsNullOrEmpty(activityName))
{
throw new ApplicationException("activity name must not be empty");
}
else if(!activityName.Contains('.'))
{
throw new ApplicationException("activity name must contain dot seperator");
}
var sb = new StringBuilder();
var xamlWriter = ActivityXamlServices.CreateBuilderWriter(new IgnorableXamlXmlWriter(new StringWriter(sb), new XamlSchemaContext()));
XamlServices.Save(xamlWriter, model.RootActivity);
var xaml = sb.ToString();
var description = model.ActivityEntity.Description;
var fileName = Path.Combine(Path.GetTempPath(), string.Format("{0}.dll", Guid.NewGuid().ToString()));
var result = this.CompileAssembly(xaml, description, activityName, fileName);
foreach (CompilerError item in result.Errors)
{
Trace.TraceError(item.ErrorText);
}
if (result.Errors.HasErrors)
{
throw new ApplicationException("Assembly could not be compiled");
}
File.Copy(fileName, Path.Combine(sourceFileName, string.Format("{0}.dll", activityName)), true);
File.Delete(fileName);
return true;
}
public bool DeleteDesignerModel(object key)
{
var fileName = Path.Combine(sourceFileName, string.Format("{0}.dll", key));
if (File.Exists(fileName))
{
File.Delete(fileName);
return true;
}
return false;
}
private CompilerResults CompileAssembly(string xaml, string description, string activityName, string fileName)
{
string source;
using (var sr = new StreamReader(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "template.txt")))
{
xaml = xaml != null ? xaml.Replace('"', char.Parse("'")) : null;
description = description != null ? description.Replace('"', char.Parse("'")) : null;
activityName = activityName != null ? activityName.Replace('"', char.Parse("'")) : null;
source = sr.ReadToEnd();
source = source.Replace("{0}", xaml);
source = source.Replace("{1}", description);
source = source.Replace("{2}", activityName);
}
var codeDomProvider = new CSharpCodeProvider();
var compilerParams = new CompilerParameters
{
OutputAssembly = fileName,
GenerateExecutable = false,
GenerateInMemory = false,
IncludeDebugInformation = false
};
compilerParams.ReferencedAssemblies.Add(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Selen.ActivityWorkflowType.dll"));
compilerParams.ReferencedAssemblies.Add("System.dll");
compilerParams.ReferencedAssemblies.Add("System.Core.dll");
compilerParams.ReferencedAssemblies.Add("System.Drawing.dll");
compilerParams.ReferencedAssemblies.Add(@"WPF\WindowsBase.dll");
compilerParams.ReferencedAssemblies.Add("System.Activities.dll");
compilerParams.ReferencedAssemblies.Add("System.Activities.Core.Presentation.dll");
compilerParams.ReferencedAssemblies.Add("System.Activities.Presentation.dll");
compilerParams.ReferencedAssemblies.Add("System.Xml.dll");
compilerParams.ReferencedAssemblies.Add("System.Xaml.dll");
return codeDomProvider.CompileAssemblyFromSource(compilerParams, source);
}
}
}