Code:
/ DotNET / DotNET / 8.0 / untmp / Orcas / RTM / ndp / fx / src / xsp / System / Web / Extensions / Compilation / WCFBuildProvider.cs / 1 / WCFBuildProvider.cs
//------------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//-----------------------------------------------------------------------------
namespace System.Web.Compilation
{
using System;
using System.Globalization;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Collections.Specialized;
using System.Diagnostics.CodeAnalysis;
using System.Net;
using System.Xml.Serialization;
using System.Web.Hosting;
using System.Web.UI;
using System.Diagnostics;
using System.Threading;
using System.Text;
using System.Web.Compilation.WCFModel;
using System.Collections.Generic;
using System.Web.Configuration;
using System.Web.Resources;
using System.Security.Permissions;
///
/// A build provider for WCF service references in ASP.NET projects.
/// (Note: the ASMX version is called WebReferencesBuildProvider).
/// Due to compatibility requirements, as few changes as possible were made
/// to System.Web.dll, which contains the build manager and WebReferencesBuildProvider.
/// WebReferencesBuildProvider will call into us for the App_WebReferences folder and
/// each of its subdirectories (recursively) if it finds our assembly and type on the
/// machine.
/// Note: for a normal BuildProvider, the input file is represented by the protected VirtualPath
/// property of the base. But for this build provider (same as for WebReferencesBuildProvider, the
/// asmx web references build provider), the input is an entire directory, which is still represented
/// by the protected VirtualPath property.
/// TO DEBUG: The easiest way to debug is to debug the aspnet_compiler.exe command-line tool
/// while it compiles a website with a .svcmap file in it.
/// As an example, you could debug aspnet_compiler.exe with this command-line to debug
/// one of the suites:
///
/// /v MiddleService -p {path}\ddsuites\src\vs\vb\IndigoTools\BuildProvider\WCFBuildProvider1\WebSite\MiddleService -c c:\temp\output
///
/// Important: it will only call the build provider if the sources in the website have changed or if you delete
/// the deleted output folder's contents.
///
///
[
AspNetHostingPermission(SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal),
AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal),
PermissionSet(SecurityAction.LinkDemand, Name="FullTrust"),
SuppressMessage("Microsoft.Naming", "CA1705:LongAcronymsShouldBePascalCased",
Justification = "Too late to change in Orcas--the WCFBuildProvider is hard-coded in ASP.NET " +
"build manager for app_webreferences folder. Build manager is part of redbits.")
]
public class WCFBuildProvider : BuildProvider
{
internal const string WebRefDirectoryName = "App_WebReferences";
internal const string SvcMapExtension = ".svcmap";
private const string TOOL_CONFIG_ITEM_NAME = "Reference.config";
///
/// version number for 3.5 framework
///
private const int FRAMEWORK_VERSION_35 = 0x30005;
///
/// Search through the folder represented by base.VirtualPath for .svcmap files. If any .svcmap
/// files are found, then generate proxy code for them into the specified assemblyBuilder.
///
/// Where to generate the proxy code
///
/// When this routine is called, it is expected that the protected VirtualPath property has
/// been set to the folder to scan for .svcmap files.
///
public override void GenerateCode(AssemblyBuilder assemblyBuilder)
{
// Go through all the svcmap files in the directory
VirtualDirectory vdir = GetVirtualDirectory(VirtualPath);
foreach (VirtualFile child in vdir.Files)
{
string extension = IO.Path.GetExtension(child.VirtualPath);
if (extension.Equals(SvcMapExtension, StringComparison.OrdinalIgnoreCase))
{
// .svcmap file found
// NOTE: the WebReferences code requires a physical path, so this feature
// cannot work with a non-file based VirtualPathProvider
string physicalPath = HostingEnvironment.MapPath(child.VirtualPath);
CodeCompileUnit codeUnit = GenerateCodeFromServiceMapFile(physicalPath);
// Add the CodeCompileUnit to the compilation
assemblyBuilder.AddCodeCompileUnit(this, codeUnit);
}
}
}
///
/// Generate code for one .svcmap file
///
/// the path to the service map file
///
///
private CodeCompileUnit GenerateCodeFromServiceMapFile(string mapFilePath)
{
try
{
string generatedNamespace = GetGeneratedNamespace();
SvcMapFileLoader loader = new SvcMapFileLoader(mapFilePath);
SvcMapFile mapFile = loader.LoadMapFile(System.IO.Path.GetFileName(mapFilePath));
HandleProxyGenerationErrors(mapFile.LoadErrors);
// We always use C# for the generated proxy
CodeDomProvider provider = System.CodeDom.Compiler.CodeDomProvider.CreateProvider("c#");
//Note: with the current implementation of the generator, it does all of its
// work in the constructor. This may change in the future.
VSWCFServiceContractGenerator generator = VSWCFServiceContractGenerator.GenerateCodeAndConfiguration(
mapFile,
GetToolConfig(mapFile, mapFilePath),
provider,
generatedNamespace,
null, //targetConfiguration
null, //configurationNamespace
new ImportExtensionServiceProvider(),
new TypeResolver(),
FRAMEWORK_VERSION_35,
typeof (System.Data.Design.TypedDataSetSchemaImporterExtensionFx35) //Always we are above framework version 3.5
);
// Determine what "name" to display to users for the service if there are any exceptions
// If generatedNamespace is empty, then we display the name of the .svcmap file.
string referenceDisplayName = String.IsNullOrEmpty(generatedNamespace) ?
System.IO.Path.GetFileName(mapFilePath) : generatedNamespace;
VerifyGeneratedCodeAndHandleErrors(referenceDisplayName, mapFile, generator.TargetCompileUnit, generator.ImportErrors, generator.ProxyGenerationErrors);
#if DEBUG
#if false
IO.TextWriter writer = new IO.StringWriter();
CodeGeneratorOptions options = new CodeGeneratorOptions();
options.BlankLinesBetweenMembers=true;
provider.GenerateCodeFromCompileUnit(generator.TargetCompileUnit, writer, options);
Debug.WriteLine("Generated proxy code:\r\n" + writer.ToString());
#endif
#endif
return generator.TargetCompileUnit;
}
catch (Exception ex)
{
string errorMessage = ex.Message;
errorMessage = String.Format(CultureInfo.CurrentCulture, "{0}: {1}", IO.Path.GetFileName(mapFilePath), errorMessage);
throw new InvalidOperationException(errorMessage, ex);
}
}
///
/// If there are errors passed in, handle them by throwing an appropriate error
///
/// IEnumerable for easier unit test accessors
private static void HandleProxyGenerationErrors(System.Collections.IEnumerable /**/ errors)
{
foreach (ProxyGenerationError generationError in errors)
{
// NOTE: the ASP.Net framework does not handle an error list, so we only give them the first error message
// all warning messages are ignored today
//
// We treat all error messages from WsdlImport and ProxyGenerator as warning messages
// The reason is that many of them are ignorable and doesn't block generating useful code.
if (!generationError.IsWarning &&
generationError.ErrorGeneratorState != WCFModel.ProxyGenerationError.GeneratorState.GenerateCode)
{
throw new InvalidOperationException(ConvertToBuildProviderErrorMessage(generationError));
}
}
}
///
/// Merge error message strings together
///
///
///
///
///
private static void CollectErrorMessages(System.Collections.IEnumerable errors, StringBuilder collectedMessages)
{
foreach (ProxyGenerationError generationError in errors)
{
if (!generationError.IsWarning)
{
if (collectedMessages.Length > 0)
{
collectedMessages.Append(Environment.NewLine);
}
collectedMessages.Append(ConvertToBuildProviderErrorMessage(generationError));
}
}
}
///
/// Format an error reported by the code generator to message string reported to the user.
///
///
///
///
private static string ConvertToBuildProviderErrorMessage(ProxyGenerationError generationError)
{
string errorMessage = generationError.Message;
if (!String.IsNullOrEmpty(generationError.MetadataFile))
{
if (generationError.LineNumber < 0)
{
errorMessage = String.Format(CultureInfo.CurrentCulture, "'{0}': {1}", generationError.MetadataFile, errorMessage);
}
else if (generationError.LinePosition < 0)
{
errorMessage = String.Format(CultureInfo.CurrentCulture, "'{0}' ({1}): {2}", generationError.MetadataFile, generationError.LineNumber, errorMessage);
}
else
{
errorMessage = String.Format(CultureInfo.CurrentCulture, "'{0}' ({1},{2}): {3}", generationError.MetadataFile, generationError.LineNumber, generationError.LinePosition, errorMessage);
}
}
return errorMessage;
}
///
/// Check the result from the code generator.
/// By default we treat all error messages from WsdlImporter as warnings,
/// and they will be ignored if valid code has been generated.
/// We may hit other errors when we parse the metadata files.
/// Those errors (which are usually because of a bad file) will not be ignored, because the user can fix them.
/// If the WsdlImporter hasn't generated any code as we expect, we have to consider some of the error messages are fatal.
/// We collect those messages and report to the user.
///
/// The name of the generated reference
/// Original Map File
/// generated code compile unit
///
///
///
private static void VerifyGeneratedCodeAndHandleErrors(
string referenceDisplayName,
SvcMapFile mapFile,
CodeCompileUnit generatedCode,
System.Collections.IEnumerable importErrors,
System.Collections.IEnumerable generatorErrors)
{
// Check and report fatal error first...
HandleProxyGenerationErrors(importErrors);
HandleProxyGenerationErrors(generatorErrors);
// if there is no fatal error, we expect valid type generated from the process
// unless there is no metadata files, or there is a service contract type sharing
if (mapFile.MetadataList.Count > 0 && mapFile.ClientOptions.ServiceContractMappingList.Count == 0)
{
if (!IsAnyTypeGenerated(generatedCode))
{
StringBuilder collectedMessages = new StringBuilder();
// merge error messages
CollectErrorMessages(importErrors, collectedMessages);
CollectErrorMessages(generatorErrors, collectedMessages);
throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, WCFModelStrings.ReferenceGroup_FailedToGenerateCode, referenceDisplayName, collectedMessages.ToString()));
}
}
}
///
/// Check whether we have generated any types
///
///
///
///
private static bool IsAnyTypeGenerated(CodeCompileUnit compileUnit)
{
if (compileUnit != null)
{
foreach (System.CodeDom.CodeNamespace codeNamespace in compileUnit.Namespaces)
{
if (codeNamespace.Types.Count > 0)
{
return true;
}
}
}
return false;
}
///
/// Retrieve a VirtualDirectory for the given virtual path
///
///
///
private VirtualDirectory GetVirtualDirectory(string virtualPath)
{
return HostingEnvironment.VirtualPathProvider.GetDirectory(VirtualPath);
}
///
/// Caculate our namespace for current VirtualPath...
///
///
///
private string GetGeneratedNamespace()
{
// First, determine the namespace to use for code generation. This is based on the
// relative path of the reference from its base App_WebReferences directory
// ... Get the virtual path to the App_WebReferences folder, e.g "/MyApp/App_WebReferences"
string rootWebRefDirVirtualPath = GetWebRefDirectoryVirtualPath();
// ... Get the folder's directory path, e.g "/MyApp/Application_WebReferences/Foo/Bar",
// where we'll look for .svcmap files
string currentSubfolderUnderWebReferences = this.VirtualPath;
if (currentSubfolderUnderWebReferences == null)
{
Debug.Fail("Shouldn't be given a null virtual path");
throw new InvalidOperationException();
}
return CalculateGeneratedNamespace(rootWebRefDirVirtualPath, currentSubfolderUnderWebReferences);
}
///
/// Determine the namespace to use for the proxy generation
///
/// The path to the App_WebReferences folder
/// The path to the current folder
///
private static string CalculateGeneratedNamespace(string webReferencesRootVirtualPath, string virtualPath)
{
// ... Ensure both folders have trailing slashes
webReferencesRootVirtualPath = VirtualPathUtility.AppendTrailingSlash(webReferencesRootVirtualPath);
virtualPath = VirtualPathUtility.AppendTrailingSlash(virtualPath);
Debug.Assert(virtualPath.StartsWith(webReferencesRootVirtualPath, StringComparison.OrdinalIgnoreCase),
"We expected to be inside the App_WebReferences folder");
// ... Determine the namespace to use, based on the directory structure where the .svcmap file
// is found.
if (webReferencesRootVirtualPath.Length == virtualPath.Length)
{
Debug.Assert(string.Equals(webReferencesRootVirtualPath, virtualPath, StringComparison.OrdinalIgnoreCase),
"We expected to be in the App_WebReferences directory");
// If it's the root WebReferences dir, use the empty namespace
return String.Empty;
}
else
{
// We're in a subdirectory of App_WebReferences.
// Get the directory's relative path from App_WebReferences, e.g. "Foo/Bar"
virtualPath = VirtualPathUtility.RemoveTrailingSlash(virtualPath).Substring(webReferencesRootVirtualPath.Length);
// Split it into chunks separated by '/'
string[] chunks = virtualPath.Split('/');
// Turn all the relevant chunks into valid namespace chunks
for (int i = 0; i < chunks.Length; i++)
{
chunks[i] = MakeValidTypeNameFromString(chunks[i]);
}
// Put the relevant chunks back together to form the namespace
return String.Join(".", chunks);
}
}
///
/// Returns the app domain's application virtual path [from HttpRuntime.AppDomainAppVPath].
/// Includes trailing slash, e.g. "/MyApp/"
///
private static string GetAppDomainAppVirtualPath()
{
string appVirtualPath = HttpRuntime.AppDomainAppVirtualPath;
if (appVirtualPath == null)
{
Debug.Fail("Shouldn't get a null app virtual path from the app domain");
throw new InvalidOperationException();
}
return VirtualPathUtility.AppendTrailingSlash(VirtualPathUtility.ToAbsolute(appVirtualPath));
}
///
/// Gets the virtual path to the application's App_WebReferences directory, e.g. "/MyApp/App_WebReferences/"
///
private static string GetWebRefDirectoryVirtualPath()
{
return VirtualPathUtility.Combine(GetAppDomainAppVirtualPath(), WebRefDirectoryName + @"\");
}
///
/// Return a valid type name from a string by changing any character
/// that's not a letter or a digit to an '_'.
///
///
///
internal static string MakeValidTypeNameFromString(string typeName)
{
if (String.IsNullOrEmpty(typeName))
throw new ArgumentNullException("typeName");
StringBuilder sb = new StringBuilder();
for (int i = 0; i < typeName.Length; i++)
{
// Make sure it doesn't start with a digit (ASURT 31134)
if (i == 0 && Char.IsDigit(typeName[0]))
sb.Append('_');
if (Char.IsLetterOrDigit(typeName[i]))
sb.Append(typeName[i]);
else
sb.Append('_');
}
// Identifier can't be a single underscore character
string validTypeName = sb.ToString();
if (validTypeName.Equals("_", StringComparison.Ordinal))
{
validTypeName = "__";
}
return validTypeName;
}
///
/// Get the appropriate tool configuration for this service reference.
///
/// If a reference.config file is present, the configuration object returned
/// will be the merged view of:
///
/// Machine Config
/// ReferenceConfig
///
/// If not reference.config file is present, the configuration object returned
/// will be a merged view of:
///
/// Machine.config
/// web.config in application's physical path...
///
///
/// SvcMapFile representing the service
///
private System.Configuration.Configuration GetToolConfig(SvcMapFile mapFile, string mapFilePath)
{
string toolConfigFile = null;
if (mapFile != null && mapFilePath != null)
{
foreach (ExtensionFile extensionFile in mapFile.Extensions)
{
if (String.Equals(extensionFile.Name, TOOL_CONFIG_ITEM_NAME, StringComparison.Ordinal))
{
toolConfigFile = extensionFile.FileName;
}
}
}
System.Web.Configuration.WebConfigurationFileMap fileMap;
fileMap = new System.Web.Configuration.WebConfigurationFileMap();
System.Web.Configuration.VirtualDirectoryMapping mapping;
if (toolConfigFile != null)
{
//
// If we've got a specific tool configuration to use, we better load that...
//
mapping = new System.Web.Configuration.VirtualDirectoryMapping(System.IO.Path.GetDirectoryName(mapFilePath), true, toolConfigFile);
}
else
{
//
// Otherwise we fall back to the default web.config file...
//
mapping = new System.Web.Configuration.VirtualDirectoryMapping(HostingEnvironment.ApplicationPhysicalPath, true);
}
fileMap.VirtualDirectories.Add("/", mapping);
return System.Web.Configuration.WebConfigurationManager.OpenMappedWebConfiguration(fileMap, "/");
}
///
/// Helper class to implement type resolution for the generator
///
private class TypeResolver : IContractGeneratorReferenceTypeLoader
{
private System.Reflection.Assembly[] _referencedAssemblies;
private IEnumerable ReferencedAssemblies
{
get
{
if (_referencedAssemblies == null)
{
System.Collections.ICollection referencedAssemblyCollection = BuildManager.GetReferencedAssemblies();
_referencedAssemblies = new System.Reflection.Assembly[referencedAssemblyCollection.Count];
referencedAssemblyCollection.CopyTo(_referencedAssemblies, 0);
}
return _referencedAssemblies;
}
}
System.Type IContractGeneratorReferenceTypeLoader.LoadType(string typeName)
{
// If the type can't be resolved, we need an exception thrown (thus the true argument)
// so it can be reported as a build error.
return BuildManager.GetType(typeName, true);
}
System.Reflection.Assembly IContractGeneratorReferenceTypeLoader.LoadAssembly(string assemblyName)
{
System.Reflection.AssemblyName assemblyToLookFor = new System.Reflection.AssemblyName(assemblyName);
foreach (System.Reflection.Assembly assembly in ReferencedAssemblies)
{
if (System.Reflection.AssemblyName.ReferenceMatchesDefinition(assemblyToLookFor, assembly.GetName()))
{
return assembly;
}
}
throw new System.IO.FileNotFoundException(String.Format(CultureInfo.CurrentCulture, WCFModelStrings.ReferenceGroup_FailedToLoadAssembly, assemblyName));
}
void IContractGeneratorReferenceTypeLoader.LoadAllAssemblies(out IEnumerable loadedAssemblies, out IEnumerable loadingErrors)
{
loadedAssemblies = ReferencedAssemblies;
loadingErrors = new System.Exception[] {};
}
}
private class ImportExtensionServiceProvider : IServiceProvider
{
#region IServiceProvider Members
public object GetService(Type serviceType)
{
// We don't currently provide any services to import extensions in the build provider context
return null;
}
#endregion
}
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- __Filters.cs
- RepeaterItemCollection.cs
- QuotedPrintableStream.cs
- UserControlBuildProvider.cs
- PageHandlerFactory.cs
- coordinatorscratchpad.cs
- LocalizedNameDescriptionPair.cs
- ConnectionConsumerAttribute.cs
- CodeArgumentReferenceExpression.cs
- SymbolMethod.cs
- PeerEndPoint.cs
- XmlChildNodes.cs
- MultipleViewPattern.cs
- FileDialog_Vista.cs
- XmlILOptimizerVisitor.cs
- TextAdaptor.cs
- BlockCollection.cs
- RectangleHotSpot.cs
- InputMethodStateChangeEventArgs.cs
- SelectionRange.cs
- ParenthesizePropertyNameAttribute.cs
- SimpleType.cs
- CommandLibraryHelper.cs
- ApplicationSecurityManager.cs
- ContourSegment.cs
- CharEntityEncoderFallback.cs
- DataConnectionHelper.cs
- RepeaterDesigner.cs
- SnapshotChangeTrackingStrategy.cs
- ValidationEventArgs.cs
- SoapAttributeOverrides.cs
- RunInstallerAttribute.cs
- SecurityRuntime.cs
- TextParaClient.cs
- ContainerActivationHelper.cs
- DataGridViewAutoSizeColumnsModeEventArgs.cs
- IntranetCredentialPolicy.cs
- OperatorExpressions.cs
- DataFieldConverter.cs
- WindowsIdentity.cs
- ModelTreeEnumerator.cs
- ObjectDataSource.cs
- DataGridViewCheckBoxCell.cs
- SourceFilter.cs
- XmlEncodedRawTextWriter.cs
- FixedDSBuilder.cs
- DataPagerCommandEventArgs.cs
- XPathConvert.cs
- EntitySqlQueryCacheKey.cs
- WorkflowOperationContext.cs
- WebPartVerbCollection.cs
- NamespaceDisplay.xaml.cs
- Group.cs
- MemoryFailPoint.cs
- ClientUrlResolverWrapper.cs
- IdnMapping.cs
- XmlAttributes.cs
- AccessDataSource.cs
- DataBindEngine.cs
- TypeLoader.cs
- sitestring.cs
- CorrelationValidator.cs
- RuntimeIdentifierPropertyAttribute.cs
- AuthenticationModuleElementCollection.cs
- HtmlEmptyTagControlBuilder.cs
- remotingproxy.cs
- Utils.cs
- SystemIcmpV4Statistics.cs
- securitycriticaldata.cs
- InternalDuplexChannelFactory.cs
- SqlConnectionStringBuilder.cs
- TickBar.cs
- AlternationConverter.cs
- WindowsSolidBrush.cs
- CodeRemoveEventStatement.cs
- CommandField.cs
- Point3DCollection.cs
- Ref.cs
- XmlSchemaAny.cs
- FileUtil.cs
- NotifyInputEventArgs.cs
- documentsequencetextcontainer.cs
- InkCanvasFeedbackAdorner.cs
- HttpServerChannel.cs
- XmlSequenceWriter.cs
- QueryOperationResponseOfT.cs
- QilInvoke.cs
- PenLineJoinValidation.cs
- ConfigXmlDocument.cs
- UnauthorizedWebPart.cs
- SqlWebEventProvider.cs
- FunctionParameter.cs
- cookiecontainer.cs
- SafeHandle.cs
- AccessibleObject.cs
- ListBase.cs
- safelinkcollection.cs
- WindowsStartMenu.cs
- AnyReturnReader.cs
- EdgeProfileValidation.cs