You've already forked linux-packaging-mono
Imported Upstream version 4.6.0.125
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
This commit is contained in:
parent
a569aebcfd
commit
e79aa3c0ed
@@ -0,0 +1,20 @@
|
||||
//------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------
|
||||
namespace System.ServiceModel.Activities.Activation
|
||||
{
|
||||
using System.ServiceModel;
|
||||
using System.ServiceModel.Activation;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime;
|
||||
|
||||
[SuppressMessage(FxCop.Category.Performance, FxCop.Rule.AvoidUninstantiatedInternalClasses,
|
||||
Justification = "This is instantiated by AspNet.")]
|
||||
class ServiceModelActivitiesActivationHandler : HttpHandler, IServiceModelActivationHandler
|
||||
{
|
||||
public ServiceHostFactoryBase GetFactory()
|
||||
{
|
||||
return new WorkflowServiceHostFactory();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
//------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------
|
||||
namespace System.ServiceModel.Activities.Activation
|
||||
{
|
||||
using System.ServiceModel;
|
||||
using System.ServiceModel.Activation;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime;
|
||||
using System.Xaml.Hosting;
|
||||
|
||||
[SuppressMessage(FxCop.Category.Performance, FxCop.Rule.AvoidUninstantiatedInternalClasses,
|
||||
Justification = "This is instantiated by AspNet.")]
|
||||
class ServiceModelActivitiesActivationHandlerAsync : ServiceHttpHandlerFactory, IServiceModelActivationHandler, IXamlBuildProviderExtensionFactory
|
||||
{
|
||||
public ServiceHostFactoryBase GetFactory()
|
||||
{
|
||||
return new WorkflowServiceHostFactory();
|
||||
}
|
||||
|
||||
public IXamlBuildProviderExtension GetXamlBuildProviderExtension()
|
||||
{
|
||||
return new XamlBuildProviderExtension();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,481 @@
|
||||
//------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------
|
||||
namespace System.ServiceModel.Activities.Activation
|
||||
{
|
||||
using System.Activities;
|
||||
using System.Activities.Expressions;
|
||||
using System.Activities.XamlIntegration;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Runtime;
|
||||
using System.Runtime.DurableInstancing;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Security;
|
||||
using System.Security.Permissions;
|
||||
using System.ServiceModel.Activation;
|
||||
using System.Text;
|
||||
using System.Web;
|
||||
using System.Web.Compilation;
|
||||
using System.Web.Hosting;
|
||||
using System.Xaml;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
|
||||
public class WorkflowServiceHostFactory : ServiceHostFactoryBase
|
||||
{
|
||||
const string SupportedVersionsGeneratedTypeNamePrefix = "SupportedVersionsGeneratedType_";
|
||||
const string SupportedVersionsFolder = "App_Code";
|
||||
string xamlVirtualFile;
|
||||
|
||||
public override ServiceHostBase CreateServiceHost(string constructorString, Uri[] baseAddresses)
|
||||
{
|
||||
WorkflowServiceHost serviceHost = null;
|
||||
|
||||
if (string.IsNullOrEmpty(constructorString))
|
||||
{
|
||||
throw FxTrace.Exception.AsError(new InvalidOperationException(SR.WorkflowServiceHostFactoryConstructorStringNotProvided));
|
||||
}
|
||||
|
||||
if (baseAddresses == null)
|
||||
{
|
||||
throw FxTrace.Exception.ArgumentNull("baseAddresses");
|
||||
}
|
||||
|
||||
if (baseAddresses.Length == 0)
|
||||
{
|
||||
throw FxTrace.Exception.AsError(new InvalidOperationException(SR.BaseAddressesNotProvided));
|
||||
}
|
||||
|
||||
if (!HostingEnvironment.IsHosted)
|
||||
{
|
||||
throw FxTrace.Exception.AsError(new InvalidOperationException(SR.Hosting_ProcessNotExecutingUnderHostedContext("WorkflowServiceHostFactory.CreateServiceHost")));
|
||||
}
|
||||
|
||||
// We expect most users will use .xamlx file instead of precompiled assembly
|
||||
// Samples of xamlVirtualPath under all scenarios
|
||||
// constructorString XamlFileBaseLocation xamlVirtualPath
|
||||
// 1. Xamlx direct ~/sub/a.xamlx ~/sub/ ~/sub/a.xamlx
|
||||
// 2. CBA with precompiled servicetypeinfo ~/sub/servicetypeinfo ~/sub/servicetypeinfo * no file will be found
|
||||
// 3. CBA with xamlx sub/a.xamlx ~/ ~/sub/a.xamlx
|
||||
// 4. Svc with precompiled servicetypeinfo ~/sub/servicetypeinfo ~/sub/servicetypeinfo * no file will be found
|
||||
// 5. Svc with Xamlx ../a.xamlx ~/sub/ ~/a.xamlx
|
||||
|
||||
string xamlVirtualPath = VirtualPathUtility.Combine(AspNetEnvironment.Current.XamlFileBaseLocation, constructorString);
|
||||
Stream activityStream;
|
||||
string compiledCustomString;
|
||||
if (GetServiceFileStreamOrCompiledCustomString(xamlVirtualPath, baseAddresses, out activityStream, out compiledCustomString))
|
||||
{
|
||||
//
|
||||
|
||||
BuildManager.GetReferencedAssemblies();
|
||||
//XmlnsMappingHelper.EnsureMappingPassed();
|
||||
|
||||
this.xamlVirtualFile = xamlVirtualPath;
|
||||
|
||||
WorkflowService service;
|
||||
using (activityStream)
|
||||
{
|
||||
string serviceName = VirtualPathUtility.GetFileName(xamlVirtualPath);
|
||||
string serviceNamespace = String.Format(CultureInfo.InvariantCulture, "/{0}{1}", ServiceHostingEnvironment.SiteName, VirtualPathUtility.GetDirectory(ServiceHostingEnvironment.FullVirtualPath));
|
||||
|
||||
service = CreatetWorkflowServiceAndSetCompiledExpressionRoot(null, activityStream, XName.Get(XmlConvert.EncodeLocalName(serviceName), serviceNamespace));
|
||||
}
|
||||
|
||||
if (service != null)
|
||||
{
|
||||
serviceHost = CreateWorkflowServiceHost(service, baseAddresses);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Type activityType = this.GetTypeFromAssembliesInCurrentDomain(constructorString);
|
||||
if (null == activityType)
|
||||
{
|
||||
activityType = GetTypeFromCompileCustomString(compiledCustomString, constructorString);
|
||||
}
|
||||
if (null == activityType)
|
||||
{
|
||||
//for file-less cases, try in referenced assemblies as CompileCustomString assemblies are empty.
|
||||
BuildManager.GetReferencedAssemblies();
|
||||
activityType = this.GetTypeFromAssembliesInCurrentDomain(constructorString);
|
||||
}
|
||||
if (null != activityType)
|
||||
{
|
||||
if (!TypeHelper.AreTypesCompatible(activityType, typeof(Activity)))
|
||||
{
|
||||
throw FxTrace.Exception.AsError(new InvalidOperationException(SR.TypeNotActivity(activityType.FullName)));
|
||||
}
|
||||
|
||||
Activity activity = (Activity)Activator.CreateInstance(activityType);
|
||||
serviceHost = CreateWorkflowServiceHost(activity, baseAddresses);
|
||||
}
|
||||
}
|
||||
if (serviceHost == null)
|
||||
{
|
||||
throw FxTrace.Exception.AsError(
|
||||
new InvalidOperationException(SR.CannotResolveConstructorStringToWorkflowType(constructorString)));
|
||||
}
|
||||
|
||||
//The Description.Name and Description.NameSpace aren't included intentionally - because
|
||||
//in farm scenarios the sole and unique identifier is the service deployment URL
|
||||
((IDurableInstancingOptions)serviceHost.DurableInstancingOptions).SetScopeName(
|
||||
XName.Get(XmlConvert.EncodeLocalName(VirtualPathUtility.GetFileName(ServiceHostingEnvironment.FullVirtualPath)),
|
||||
String.Format(CultureInfo.InvariantCulture, "/{0}{1}", ServiceHostingEnvironment.SiteName, VirtualPathUtility.GetDirectory(ServiceHostingEnvironment.FullVirtualPath))));
|
||||
|
||||
return serviceHost;
|
||||
}
|
||||
|
||||
internal static object LoadXaml(Stream activityStream)
|
||||
{
|
||||
object serviceObject;
|
||||
XamlXmlReaderSettings xamlXmlReaderSettings = new XamlXmlReaderSettings();
|
||||
xamlXmlReaderSettings.ProvideLineInfo = true;
|
||||
XamlReader wrappedReader = ActivityXamlServices.CreateReader(new XamlXmlReader(XmlReader.Create(activityStream), xamlXmlReaderSettings));
|
||||
if (TD.XamlServicesLoadStartIsEnabled())
|
||||
{
|
||||
TD.XamlServicesLoadStart();
|
||||
}
|
||||
serviceObject = XamlServices.Load(wrappedReader);
|
||||
if (TD.XamlServicesLoadStopIsEnabled())
|
||||
{
|
||||
TD.XamlServicesLoadStop();
|
||||
}
|
||||
return serviceObject;
|
||||
}
|
||||
|
||||
void AddSupportedVersions(WorkflowServiceHost workflowServiceHost, WorkflowService baseService)
|
||||
{
|
||||
AspNetPartialTrustHelpers.FailIfInPartialTrustOutsideAspNet();
|
||||
|
||||
IList<Tuple<string, Stream>> streams = null;
|
||||
string xamlFileName = Path.GetFileNameWithoutExtension(VirtualPathUtility.GetFileName(this.xamlVirtualFile));
|
||||
GetSupportedVersionStreams(xamlFileName, out streams);
|
||||
|
||||
if (streams != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
foreach (Tuple<string, Stream> stream in streams)
|
||||
{
|
||||
try
|
||||
{
|
||||
WorkflowService service = CreatetWorkflowServiceAndSetCompiledExpressionRoot(stream.Item1, stream.Item2, baseService.Name);
|
||||
if (service != null)
|
||||
{
|
||||
workflowServiceHost.SupportedVersions.Add(service);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Exception newException;
|
||||
if (Fx.IsFatal(e) || !TryWrapSupportedVersionException(stream.Item1, e, out newException))
|
||||
{
|
||||
throw;
|
||||
}
|
||||
|
||||
throw FxTrace.Exception.AsError(newException);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
foreach (Tuple<string, Stream> stream in streams)
|
||||
{
|
||||
stream.Item2.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static bool TryWrapSupportedVersionException(string filePath, Exception e, out Exception newException)
|
||||
{
|
||||
// We replace the exception, rather than simply wrapping it, because the activation error page highlights
|
||||
// the innermost exception, and we want that exception to clearly show which file is the culprit.
|
||||
// Of course, if the exception has an inner exception, that will still get highlighted instead.
|
||||
// Also, for Xaml and XmlException, we don't propagate the line info, because the exception message already contains it.
|
||||
if (e is XmlException)
|
||||
{
|
||||
newException = new XmlException(SR.ExceptionLoadingSupportedVersion(filePath, e.Message), e.InnerException);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (e is XamlException)
|
||||
{
|
||||
newException = new XamlException(SR.ExceptionLoadingSupportedVersion(filePath, e.Message), e.InnerException);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (e is InvalidWorkflowException)
|
||||
{
|
||||
newException = new InvalidWorkflowException(SR.ExceptionLoadingSupportedVersion(filePath, e.Message), e.InnerException);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (e is ValidationException)
|
||||
{
|
||||
newException = new ValidationException(SR.ExceptionLoadingSupportedVersion(filePath, e.Message), e.InnerException);
|
||||
return true;
|
||||
}
|
||||
|
||||
newException = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
internal static string GetSupportedVersionGeneratedTypeName(string filePath)
|
||||
{
|
||||
string activityName = Path.GetFileNameWithoutExtension(filePath).ToUpper(CultureInfo.InvariantCulture);
|
||||
|
||||
StringBuilder sb = new StringBuilder(WorkflowServiceHostFactory.SupportedVersionsGeneratedTypeNamePrefix);
|
||||
for (int i = 0; i < activityName.Length; i++)
|
||||
{
|
||||
sb.Append(char.ConvertToUtf32(activityName, i));
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
[Fx.Tag.SecurityNote(Critical = "Calls SecurityCritical method HostingEnvironmentWrapper.UnsafeImpersonate().",
|
||||
Safe = "Demands unmanaged code permission, disposes impersonation context in a finally, and tightly scopes the usage of the impersonation token.")]
|
||||
[SecurityPermission(SecurityAction.Demand, UnmanagedCode = true)]
|
||||
[SecuritySafeCritical]
|
||||
internal static void GetSupportedVersionStreams(string xamlFileName, out IList<Tuple<string, Stream>> streams)
|
||||
{
|
||||
AspNetPartialTrustHelpers.FailIfInPartialTrustOutsideAspNet();
|
||||
|
||||
string virtualFileFolder = string.Format(CultureInfo.InvariantCulture, "~\\{0}", Path.Combine(SupportedVersionsFolder, xamlFileName));
|
||||
IDisposable unsafeImpersonate = null;
|
||||
List<Tuple<string, Stream>> streamList = new List<Tuple<string, Stream>>();
|
||||
bool cleanExit = false;
|
||||
streams = null;
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
finally
|
||||
{
|
||||
unsafeImpersonate = HostingEnvironmentWrapper.UnsafeImpersonate();
|
||||
}
|
||||
|
||||
if (HostingEnvironment.VirtualPathProvider.DirectoryExists(virtualFileFolder))
|
||||
{
|
||||
string xamlFileFolder = HostingEnvironmentWrapper.MapPath(virtualFileFolder);
|
||||
string[] files = Directory.GetFiles(xamlFileFolder, "*.xamlx");
|
||||
foreach (string file in files)
|
||||
{
|
||||
Stream activityStream;
|
||||
string path = Path.Combine(SupportedVersionsFolder, xamlFileName, Path.GetFileName(file));
|
||||
string virtualFile = string.Format(CultureInfo.InvariantCulture, "~\\{0}", path);
|
||||
|
||||
if (HostingEnvironment.VirtualPathProvider.FileExists(virtualFile))
|
||||
{
|
||||
activityStream = HostingEnvironment.VirtualPathProvider.GetFile(virtualFile).Open();
|
||||
streamList.Add(Tuple.Create(path, activityStream));
|
||||
}
|
||||
}
|
||||
}
|
||||
cleanExit = true;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (unsafeImpersonate != null)
|
||||
{
|
||||
unsafeImpersonate.Dispose();
|
||||
unsafeImpersonate = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
cleanExit = false;
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (cleanExit)
|
||||
{
|
||||
streams = streamList;
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (Tuple<string, Stream> stream in streamList)
|
||||
{
|
||||
stream.Item2.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static WorkflowService CreatetWorkflowServiceAndSetCompiledExpressionRoot(string supportedVersionXamlxfilePath, Stream activityStream, XName defaultServiceName)
|
||||
{
|
||||
WorkflowService service = CreatetWorkflowService(activityStream, defaultServiceName);
|
||||
if (service != null)
|
||||
{
|
||||
// CompiledExpression is not supported on Configuration Based Activation (CBA) scenario.
|
||||
if (ServiceHostingEnvironment.IsHosted && !ServiceHostingEnvironment.IsConfigurationBased)
|
||||
{
|
||||
// We use ServiceHostingEnvironment.FullVirtualPath (instead of the constructor string) because we<77>re passing this path to BuildManager,
|
||||
// which may not understand the file type referenced by the constructor string (e.g. .xaml).
|
||||
ICompiledExpressionRoot expressionRoot = XamlBuildProviderExtension.GetExpressionRoot(supportedVersionXamlxfilePath, service, ServiceHostingEnvironment.FullVirtualPath);
|
||||
if (expressionRoot != null)
|
||||
{
|
||||
CompiledExpressionInvoker.SetCompiledExpressionRoot(service.Body, expressionRoot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return service;
|
||||
}
|
||||
|
||||
internal static WorkflowService CreatetWorkflowService(Stream activityStream, XName defaultServiceName)
|
||||
{
|
||||
WorkflowService service = null;
|
||||
object serviceObject;
|
||||
|
||||
serviceObject = LoadXaml(activityStream);
|
||||
|
||||
if (serviceObject is Activity)
|
||||
{
|
||||
service = new WorkflowService
|
||||
{
|
||||
Body = (Activity)serviceObject
|
||||
};
|
||||
}
|
||||
else if (serviceObject is WorkflowService)
|
||||
{
|
||||
service = (WorkflowService)serviceObject;
|
||||
}
|
||||
|
||||
// If name of the service is not set
|
||||
// service name = xaml file name with extension
|
||||
// service namespace = IIS virtual path
|
||||
// service config name = Activity.DisplayName
|
||||
if (service != null)
|
||||
{
|
||||
if (service.Name == null)
|
||||
{
|
||||
service.Name = defaultServiceName;
|
||||
|
||||
if (service.ConfigurationName == null && service.Body != null)
|
||||
{
|
||||
service.ConfigurationName = XmlConvert.EncodeLocalName(service.Body.DisplayName);
|
||||
}
|
||||
}
|
||||
}
|
||||
return service;
|
||||
}
|
||||
|
||||
Type GetTypeFromAssembliesInCurrentDomain(string typeString)
|
||||
{
|
||||
Type activityType = Type.GetType(typeString, false);
|
||||
if (null == activityType)
|
||||
{
|
||||
foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
|
||||
{
|
||||
activityType = assembly.GetType(typeString, false);
|
||||
if (null != activityType)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return activityType;
|
||||
}
|
||||
|
||||
Type GetTypeFromCompileCustomString(string compileCustomString, string typeString)
|
||||
{
|
||||
if (string.IsNullOrEmpty(compileCustomString))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
string[] components = compileCustomString.Split('|');
|
||||
if (components.Length < 3)
|
||||
{
|
||||
throw FxTrace.Exception.AsError(new InvalidOperationException(SR.InvalidCompiledString(compileCustomString)));
|
||||
}
|
||||
Type activityType = null;
|
||||
for (int i = 3; i < components.Length; i++)
|
||||
{
|
||||
Assembly assembly = Assembly.Load(components[i]);
|
||||
activityType = assembly.GetType(typeString, false);
|
||||
if (activityType != null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
return activityType;
|
||||
}
|
||||
|
||||
protected virtual WorkflowServiceHost CreateWorkflowServiceHost(Activity activity, Uri[] baseAddresses)
|
||||
{
|
||||
return new WorkflowServiceHost(activity, baseAddresses);
|
||||
}
|
||||
|
||||
protected virtual WorkflowServiceHost CreateWorkflowServiceHost(WorkflowService service, Uri[] baseAddresses)
|
||||
{
|
||||
WorkflowServiceHost workflowServiceHost = new WorkflowServiceHost(service, baseAddresses);
|
||||
if (service.DefinitionIdentity != null)
|
||||
{
|
||||
AddSupportedVersions(workflowServiceHost, service);
|
||||
}
|
||||
return workflowServiceHost;
|
||||
}
|
||||
|
||||
// The code is optimized for reducing impersonation
|
||||
// true means serviceFileStream has been set; false means CompiledCustomString has been set
|
||||
[Fx.Tag.SecurityNote(Critical = "Calls SecurityCritical method HostingEnvironmentWrapper.UnsafeImpersonate().",
|
||||
Safe = "Demands unmanaged code permission, disposes impersonation context in a finally, and tightly scopes the usage of the impersonation token.")]
|
||||
[SecurityPermission(SecurityAction.Demand, UnmanagedCode = true)]
|
||||
[SecuritySafeCritical]
|
||||
bool GetServiceFileStreamOrCompiledCustomString(string virtualPath, Uri[] baseAddresses, out Stream serviceFileStream, out string compiledCustomString)
|
||||
{
|
||||
AspNetPartialTrustHelpers.FailIfInPartialTrustOutsideAspNet();
|
||||
|
||||
IDisposable unsafeImpersonate = null;
|
||||
compiledCustomString = null;
|
||||
serviceFileStream = null;
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
finally
|
||||
{
|
||||
unsafeImpersonate = HostingEnvironmentWrapper.UnsafeImpersonate();
|
||||
}
|
||||
if (HostingEnvironment.VirtualPathProvider.FileExists(virtualPath))
|
||||
{
|
||||
serviceFileStream = HostingEnvironment.VirtualPathProvider.GetFile(virtualPath).Open();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!AspNetEnvironment.Current.IsConfigurationBased)
|
||||
{
|
||||
compiledCustomString = BuildManager.GetCompiledCustomString(baseAddresses[0].AbsolutePath);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (null != unsafeImpersonate)
|
||||
{
|
||||
unsafeImpersonate.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,251 @@
|
||||
//------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------
|
||||
|
||||
namespace System.ServiceModel.Activities.Activation
|
||||
{
|
||||
using System.Activities;
|
||||
using System.Activities.XamlIntegration;
|
||||
using System.CodeDom;
|
||||
using System.CodeDom.Compiler;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Runtime;
|
||||
using System.ServiceModel.Activation;
|
||||
using System.Web;
|
||||
using System.Web.Compilation;
|
||||
|
||||
sealed class XamlBuildProviderExtension : System.Xaml.Hosting.IXamlBuildProviderExtension
|
||||
{
|
||||
const string GeneratedNamespace = "GeneratedNamespace";
|
||||
const string ExpressionRootFactorySuffix = "_ExpressionRootFactory";
|
||||
const string CreateExpressionRootMethodName = "CreateExpressionRoot";
|
||||
const string ActivityParameterName = "activity";
|
||||
|
||||
string generatedPrimaryTypeName;
|
||||
|
||||
internal XamlBuildProviderExtension()
|
||||
{
|
||||
AspNetPartialTrustHelpers.FailIfInPartialTrustOutsideAspNet();
|
||||
}
|
||||
|
||||
public void GenerateCode(AssemblyBuilder assemblyBuilder, Stream xamlStream, BuildProvider buildProvider)
|
||||
{
|
||||
object serviceObject = WorkflowServiceHostFactory.LoadXaml(xamlStream);
|
||||
|
||||
WorkflowService workflowService = serviceObject as WorkflowService;
|
||||
if (workflowService != null && workflowService.Body != null)
|
||||
{
|
||||
string activityName;
|
||||
if (this.TryGenerateSource(assemblyBuilder, buildProvider, workflowService, false, null, out activityName))
|
||||
{
|
||||
this.generatedPrimaryTypeName = GeneratedNamespace + "." + activityName + ExpressionRootFactorySuffix;
|
||||
}
|
||||
|
||||
// find all supported versions xamlx files, load and compile them
|
||||
IList<Tuple<string, Stream>> streams = null;
|
||||
|
||||
string xamlVirtualFile = GetXamlVirtualPath(buildProvider);
|
||||
string xamlFileName = Path.GetFileNameWithoutExtension(VirtualPathUtility.GetFileName(xamlVirtualFile));
|
||||
WorkflowServiceHostFactory.GetSupportedVersionStreams(xamlFileName, out streams);
|
||||
if (streams != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
foreach (Tuple<string, Stream> stream in streams)
|
||||
{
|
||||
try
|
||||
{
|
||||
WorkflowService service = WorkflowServiceHostFactory.CreatetWorkflowService(stream.Item2, workflowService.Name);
|
||||
if (service != null && service.Body != null)
|
||||
{
|
||||
this.TryGenerateSource(assemblyBuilder, buildProvider, service, true, stream.Item1, out activityName);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Exception newException;
|
||||
if (Fx.IsFatal(e) || !WorkflowServiceHostFactory.TryWrapSupportedVersionException(stream.Item1, e, out newException))
|
||||
{
|
||||
throw;
|
||||
}
|
||||
|
||||
throw FxTrace.Exception.AsError(newException);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
foreach (Tuple<string, Stream> stream in streams)
|
||||
{
|
||||
stream.Item2.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Type GetGeneratedType(CompilerResults results)
|
||||
{
|
||||
if (this.generatedPrimaryTypeName != null)
|
||||
{
|
||||
return results.CompiledAssembly.GetType(this.generatedPrimaryTypeName);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// if the 1st parameter "supportedVersionXamlxfilePath" is null, we fall back to the primary generated type
|
||||
internal static ICompiledExpressionRoot GetExpressionRoot(string supportedVersionXamlxfilePath, WorkflowService service, string virtualPath)
|
||||
{
|
||||
Assembly compiledAssembly = BuildManager.GetCompiledAssembly(virtualPath);
|
||||
if (compiledAssembly == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
Type generatedType;
|
||||
if (supportedVersionXamlxfilePath != null)
|
||||
{
|
||||
string fullTypeNameToSearch = GeneratedNamespace + "." + WorkflowServiceHostFactory.GetSupportedVersionGeneratedTypeName(supportedVersionXamlxfilePath) + ExpressionRootFactorySuffix;
|
||||
generatedType = compiledAssembly.GetType(fullTypeNameToSearch);
|
||||
}
|
||||
else
|
||||
{
|
||||
generatedType = BuildManager.GetCompiledType(virtualPath);
|
||||
}
|
||||
|
||||
Type workflowServiceType = typeof(WorkflowService);
|
||||
if (generatedType != workflowServiceType && workflowServiceType.IsAssignableFrom(generatedType))
|
||||
{
|
||||
MethodInfo createExpressionRootMethod = generatedType.GetMethod(CreateExpressionRootMethodName, BindingFlags.Public | BindingFlags.Static);
|
||||
if (createExpressionRootMethod != null)
|
||||
{
|
||||
return (ICompiledExpressionRoot)createExpressionRootMethod.Invoke(null, new object[] { service.Body });
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
bool TryGenerateSource(AssemblyBuilder assemblyBuilder, BuildProvider buildProvider, WorkflowService workflowService, bool isSupportedVersion, string filePath, out string activityName)
|
||||
{
|
||||
bool generatedSource;
|
||||
string codeFileName;
|
||||
this.GenerateSource(isSupportedVersion, filePath, assemblyBuilder, workflowService, out codeFileName, out generatedSource, out activityName);
|
||||
|
||||
if (generatedSource)
|
||||
{
|
||||
this.WriteCodeFile(assemblyBuilder, buildProvider, codeFileName);
|
||||
this.GenerateExpressionRootFactory(assemblyBuilder, buildProvider, GeneratedNamespace, activityName);
|
||||
}
|
||||
|
||||
return generatedSource;
|
||||
}
|
||||
|
||||
void GenerateExpressionRootFactory(AssemblyBuilder assemblyBuilder, BuildProvider buildProvider, string activityNamespace, string activityName)
|
||||
{
|
||||
CodeCompileUnit codeCompileUnit = new CodeCompileUnit();
|
||||
|
||||
// namespace <%= activityNamespace %>
|
||||
// {
|
||||
// public class <%= activityName %>_ExpressionRootFactory : System.ServiceModel.Activities.WorkflowService
|
||||
// {
|
||||
// public static System.Activities.XamlIntegration.ICompiledExpressionRoot CreateExpressionRoot(System.Activities.Activity activity)
|
||||
// {
|
||||
// return new <%= activityNamespace %>.<%= activityName %>(activity);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
CodeNamespace codeNamespace = new CodeNamespace(activityNamespace);
|
||||
CodeTypeDeclaration codeTypeDeclaration = new CodeTypeDeclaration(activityName + ExpressionRootFactorySuffix);
|
||||
codeTypeDeclaration.BaseTypes.Add(new CodeTypeReference(typeof(WorkflowService)));
|
||||
|
||||
CodeMemberMethod codeMemberMethod = new CodeMemberMethod();
|
||||
codeMemberMethod.Name = CreateExpressionRootMethodName;
|
||||
codeMemberMethod.Attributes = MemberAttributes.Public | MemberAttributes.Static;
|
||||
codeMemberMethod.ReturnType = new CodeTypeReference(typeof(ICompiledExpressionRoot));
|
||||
codeMemberMethod.Parameters.Add(new CodeParameterDeclarationExpression(
|
||||
new CodeTypeReference(typeof(Activity)),
|
||||
ActivityParameterName));
|
||||
|
||||
CodeTypeReference typeRef = new CodeTypeReference(activityNamespace + "." + activityName);
|
||||
CodeObjectCreateExpression expr = new CodeObjectCreateExpression(typeRef, new CodeArgumentReferenceExpression(ActivityParameterName));
|
||||
codeMemberMethod.Statements.Add(new CodeMethodReturnStatement(expr));
|
||||
|
||||
codeTypeDeclaration.Members.Add(codeMemberMethod);
|
||||
codeNamespace.Types.Add(codeTypeDeclaration);
|
||||
codeCompileUnit.Namespaces.Add(codeNamespace);
|
||||
|
||||
assemblyBuilder.AddCodeCompileUnit(buildProvider, codeCompileUnit);
|
||||
}
|
||||
|
||||
void GenerateSource(bool isSupportedVersion, string filePath, AssemblyBuilder assemblyBuilder, WorkflowService workflowService, out string codeFileName, out bool generatedSource, out string activityName)
|
||||
{
|
||||
// Get unique file and type name for the workflowservice
|
||||
codeFileName = assemblyBuilder.GetTempFilePhysicalPath(assemblyBuilder.CodeDomProvider.FileExtension);
|
||||
|
||||
if (isSupportedVersion)
|
||||
{
|
||||
activityName = WorkflowServiceHostFactory.GetSupportedVersionGeneratedTypeName(filePath);
|
||||
}
|
||||
else
|
||||
{
|
||||
activityName = workflowService.Name.LocalName + "_" + Guid.NewGuid().ToString().Replace("-", "_");
|
||||
}
|
||||
|
||||
TextExpressionCompilerSettings settings = new TextExpressionCompilerSettings
|
||||
{
|
||||
Activity = workflowService.Body,
|
||||
ActivityName = activityName,
|
||||
ActivityNamespace = GeneratedNamespace,
|
||||
Language = CodeDomProvider.GetLanguageFromExtension(assemblyBuilder.CodeDomProvider.FileExtension),
|
||||
GenerateAsPartialClass = false,
|
||||
AlwaysGenerateSource = false,
|
||||
ForImplementation = false
|
||||
};
|
||||
|
||||
TextExpressionCompiler compiler = new TextExpressionCompiler(settings);
|
||||
|
||||
generatedSource = false;
|
||||
using (StreamWriter fileStream = new StreamWriter(codeFileName))
|
||||
{
|
||||
try
|
||||
{
|
||||
generatedSource = compiler.GenerateSource(fileStream);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (Fx.IsFatal(ex))
|
||||
{
|
||||
throw;
|
||||
}
|
||||
|
||||
throw FxTrace.Exception.AsError(new HttpCompileException(SR.XamlBuildProviderExtensionException(ex.Message)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WriteCodeFile(AssemblyBuilder assemblyBuilder, BuildProvider buildProvider, string name)
|
||||
{
|
||||
using (TextWriter codeFile = assemblyBuilder.CreateCodeFile(buildProvider))
|
||||
{
|
||||
foreach (string line in File.ReadLines(name))
|
||||
{
|
||||
codeFile.WriteLine(line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// XamlBuildProvider is defined in a non-APTCA assembly and this aptca method calls it. This allows partially trusted callers to indirectly
|
||||
// call the XamlBuildProvider.VirtualPath property (that requires full trust to call directly). This is safe because this private method
|
||||
// does not directly or indirectly allows users to access sensitive information, operations, or resources that can be used in a destructive manner.
|
||||
[SuppressMessage(FxCop.Category.Security, FxCop.Rule.AptcaMethodsShouldOnlyCallAptcaMethods, Justification = "The XamlBuildProvider.VirtualPath non-aptca property cannot be used in a destructive manner.")]
|
||||
private string GetXamlVirtualPath(BuildProvider buildProvider)
|
||||
{
|
||||
return ((System.Xaml.Hosting.XamlBuildProvider)buildProvider).VirtualPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user