Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / DataWeb / Design / system / Data / EntityModel / DataServiceBuildProvider.cs / 1305376 / DataServiceBuildProvider.cs
//------------------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // //----------------------------------------------------------------------------- // Putting the build provider in the System.Data.Services.Design namespace forces DataSvcUtil.exe to also take dependency on System.Web.dll // Hence putting this in a different namespace. [module: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1020:AvoidNamespacesWithFewTypes", Scope = "namespace", Target = "System.Data.Services.BuildProvider")] namespace System.Data.Services.BuildProvider { using System; using System.Collections; using System.Data.Services.Design; using System.Diagnostics; using System.Globalization; using System.IO; using System.Text; using System.Web; using System.Web.Compilation; using System.Web.Hosting; using System.Xml; using System.Xml.Schema; ////// A build provider for data service references in website projects. /// Data services (Astoria): in order to support Astoria "data services" we added code /// to scan for "datasvcmap" files in addition to the existing "svcmap" files. For data services /// we call into the Astoria code-gen library to do the work instead of the regular indigo path. /// /// [FolderLevelBuildProviderAppliesTo(FolderLevelBuildProviderAppliesTo.WebReferences)] [System.Security.SecurityCritical] public class DataServiceBuildProvider : BuildProvider { private const string WebRefDirectoryName = "App_WebReferences"; private const string DataSvcMapExtension = ".datasvcmap"; private const string UseCollectionParameterName = "UseDataServiceCollection"; private const string VersionParameterName = "Version"; private const string Version1Dot0 = "1.0"; private const string Version2Dot0 = "2.0"; ////// Search through the folder represented by base.VirtualPath for .svcmap and .datasvcmap files. /// If any .svcmap/.datasvcmap 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/.datasvcmap files. /// [System.Security.SecuritySafeCritical] 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(DataSvcMapExtension, StringComparison.OrdinalIgnoreCase)) { // 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); GenerateCodeFromDataServiceMapFile(physicalPath, assemblyBuilder); } } } ////// Generate code for one .datasvcmap file /// /// The physical path to the data service map file [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "XmlReader over StringReader doesn't need to be disposed")] private void GenerateCodeFromDataServiceMapFile(string mapFilePath, AssemblyBuilder assemblyBuilder) { try { MapFileLoader loader = new MapFileLoader(mapFilePath); loader.LoadDataSvcMapFile(); MapFileLoader.AddAssemblyReferences(assemblyBuilder, loader.UseDataServiceCollection); string edmxContent = loader.GetEdmxContent(); System.Data.Services.Design.EntityClassGenerator generator = new System.Data.Services.Design.EntityClassGenerator(LanguageOption.GenerateCSharpCode); // the EntityClassGenerator works on streams/writers, does not return a CodeDom // object, so we use CreateCodeFile instead of compile units. using (TextWriter writer = assemblyBuilder.CreateCodeFile(this)) { generator.UseDataServiceCollection = loader.UseDataServiceCollection; generator.Version = loader.Version; // Note: currently GenerateCode never actually returns values // for the error case (even though it returns an IList of error // objects). Instead it throws on error. This may need some tweaking // later on. #if DEBUG object errors = #endif generator.GenerateCode( XmlReader.Create(new StringReader(edmxContent)), writer, GetGeneratedNamespace()); #if DEBUG Debug.Assert( errors == null || !(errors is ICollection) || ((ICollection)errors).Count == 0, "Errors reported through the return value. Expected an exception"); #endif writer.Flush(); } } catch (Exception ex) { string errorMessage = ex.Message; errorMessage = String.Format(CultureInfo.CurrentCulture, "{0}: {1}", IO.Path.GetFileName(mapFilePath), errorMessage); throw new InvalidOperationException(errorMessage, ex); } } ////// 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; } private class MapFileLoader { /// Namespace for the dataSvcMap file. private const string dataSvcSchemaNamespace = "urn:schemas-microsoft-com:xml-dataservicemap"; ///xsd Schema for the datasvcmap file private static XmlSchemaSet serviceMapSchemaSet; ///xsd Schema for the datasvcmap file private static XmlNamespaceManager namespaceManager; ///full path of the data svc map file. private string dataSvcMapFilePath; ///Name of the edmx schema file. private string edmxSchemaFileName; ///True if DataServiceCollection needs to be used, otherwise false. private bool useDataServiceCollection; ///Version as specified in the svcmap file. private DataServiceCodeVersion version; ////// Creates the new instance of the dataSvcMapFileLoader. /// /// filePath for the dataSvcMap file. internal MapFileLoader(string mapFilePath) { Debug.Assert(!String.IsNullOrEmpty(mapFilePath), "mapFilePath cannot be null or empty"); this.dataSvcMapFilePath = mapFilePath; } ///True if the binding code needs to be generated, otherwise false. internal bool UseDataServiceCollection { get { return this.useDataServiceCollection; } } ///Returns the version as specified in the svcmap file. internal DataServiceCodeVersion Version { get { return this.version; } } ////// Returns the XMlSchemaSet against which the dataSvcMap needs to be validated against. /// private static XmlSchemaSet ServiceMapSchemaSet { get { if (serviceMapSchemaSet == null) { XmlSchema serviceMapSchema; System.IO.Stream fileStream = typeof(WCFBuildProvider).Assembly.GetManifestResourceStream(@"System.Web.Compilation.WCFModel.Schema.DataServiceMapSchema.xsd"); System.Diagnostics.Debug.Assert(fileStream != null, "Couldn't find ServiceMapSchema.xsd resource"); serviceMapSchema = XmlSchema.Read(fileStream, null); serviceMapSchemaSet = new XmlSchemaSet(); serviceMapSchemaSet.Add(serviceMapSchema); } return serviceMapSchemaSet; } } ////// Returns the namespace manager for the dataSvcMap file. /// private static XmlNamespaceManager NamespaceManager { get { if (namespaceManager == null) { namespaceManager = new XmlNamespaceManager(new NameTable()); namespaceManager.AddNamespace("ds", dataSvcSchemaNamespace); } return namespaceManager; } } ////// Read the contents from the edmx file. /// ///a string instance containing all the contents of the edmx file. internal string GetEdmxContent() { string edmxFilePath = IO.Path.Combine(IO.Path.GetDirectoryName(this.dataSvcMapFilePath), this.edmxSchemaFileName); return IO.File.ReadAllText(edmxFilePath); } ////// Load the DataSvcMapFile from the given location /// internal void LoadDataSvcMapFile() { using (System.IO.TextReader mapFileReader = IO.File.OpenText(this.dataSvcMapFilePath)) { XmlDocument document = LoadAndValidateFile(mapFileReader); this.edmxSchemaFileName = GetMetadataFileNameFromMapFile(document); ValidateParametersInMapFile(document, out this.version, out this.useDataServiceCollection); } } ////// Add the assembly references to the assembly builder depending on whether the databinding is enabled or not. /// /// instance of assemblyBuilder where we need to add assembly references. /// indicates whether databinding is enabled or not. internal static void AddAssemblyReferences(AssemblyBuilder assemblyBuilder, bool useDataServiceCollection) { assemblyBuilder.AddAssemblyReference(typeof(System.Data.Services.Client.DataServiceContext).Assembly); if (useDataServiceCollection) { // TODO: SQLBUDT 707098 - Use the helper method which returns the FrameworkName instance as defined in System.Runtime.Versioning namespace. // When generating data binding code for .Net framework 3.5, we need to load the right version of windows base here. // 3.5 Framework version: WindowsBase, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35 // In 4.0, ObservableCollection<> class was moved into System.dll. Hence no need to do anything. if (BuildManager.TargetFramework.Version.Major < 4) { assemblyBuilder.AddAssemblyReference(System.Reflection.Assembly.Load("WindowsBase, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35")); } } } ////// Validates the given map file. /// /// instance of text reader containing the map file. ///returns an instance of XmlDocument containing the map file. private static XmlDocument LoadAndValidateFile(TextReader mapFileReader) { XmlReaderSettings readerSettings = new XmlReaderSettings(); readerSettings.Schemas = ServiceMapSchemaSet; readerSettings.ValidationType = ValidationType.Schema; readerSettings.ValidationFlags = XmlSchemaValidationFlags.ReportValidationWarnings; // Validation Handler ValidationEventHandler handler = delegate(object sender, System.Xml.Schema.ValidationEventArgs e) { if (e.Severity == XmlSeverityType.Error) { throw e.Exception; } }; // Create an xmlDocument and load the map file XmlDocument document = new XmlDocument(); document.Load(mapFileReader); // validate the map file against the xsd document.Schemas = ServiceMapSchemaSet; document.Validate(handler); return document; } ////// Gets the metadata file name from the map file. /// /// instance of xml document which refers to the map file. ///returns the metadata file path as specified in the map file. private static string GetMetadataFileNameFromMapFile(XmlDocument document) { // The xsd already validates that there should be exactly one MetadataFile element present. XmlNode node = document.SelectSingleNode("/ds:ReferenceGroup/ds:Metadata/ds:MetadataFile", NamespaceManager); Debug.Assert(node != null, "MetadataFile node must be present"); // Both the attributes FileName and MetadataType must be present, // since the xsd already does this validation. // xsd also does the validation that these attributes cannot be empty. string edmxSchemaFileName = node.Attributes["FileName"].Value; string metadataType = node.Attributes["MetadataType"].Value; // Ideally, this check must be moved in the xsd, so that user gets all the information about where // exactly the error is - file information, line number etc. We currently only have file information // with us if (metadataType != "Edmx") { throw new ArgumentException(Strings.InvalidMetadataType(metadataType, "MetadataType", "Edmx")); } return edmxSchemaFileName; } ////// Validate the parameters list in the map file. Currently only EnableDataBinding parameter is supported. /// /// instance of xml documents which contains the map file. ///returns true if the data binding parameter is specified and its value is true, otherwise returns false. private static void ValidateParametersInMapFile(XmlDocument document, out DataServiceCodeVersion version, out bool useDataServiceCollection) { bool isSentinalTypePresent = BuildManager.GetType("System.Data.Services.Client.DataServiceCollection`1", false /*throwOnError*/) != null; // Validate all the parameters specified in the map file XmlNodeList parameters = document.SelectNodes("/ds:ReferenceGroup/ds:Parameters/ds:Parameter", NamespaceManager); bool? useCollectionParamValue = null; DataServiceCodeVersion? versionParamValue = null; if (parameters != null && parameters.Count != 0) { // currently only one parameter can be specified. EnableDataBinding - whose valid values are 'true and 'false' foreach (XmlNode p in parameters) { // Name and value attributes must be present, since they are verified by the xsd XmlAttribute nameAttribute = p.Attributes["Name"]; XmlAttribute valueAttribute = p.Attributes["Value"]; if (nameAttribute.Value == VersionParameterName) { ValidateVersionParameter(ref versionParamValue, valueAttribute.Value); } else if (nameAttribute.Value == UseCollectionParameterName) { ValidateBooleanParameter(ref useCollectionParamValue, valueAttribute.Value, UseCollectionParameterName); } else { throw new ArgumentException( Strings.InvalidParameterName( nameAttribute.Value, String.Format(CultureInfo.InvariantCulture, "'{0}', '{1}'", VersionParameterName, UseCollectionParameterName))); } } } if (!isSentinalTypePresent && useCollectionParamValue.HasValue && useCollectionParamValue == true) { throw new ArgumentException(Strings.UseDataServiceCollectionCannotBeSetToTrue(UseCollectionParameterName)); } version = versionParamValue.HasValue ? versionParamValue.Value : DataServiceCodeVersion.V1; useDataServiceCollection = useCollectionParamValue.HasValue ? useCollectionParamValue.Value : false; } ////// Validate the boolean parameter value as specified in the .svcmap file. /// /// parameter value as specified in the svcmap file. /// name of the parameter whose value is getting validated. ///boolean value as specified in the svcmap file. private static void ValidateBooleanParameter(ref bool? paramValue, string value, string parameterName) { if (paramValue == null) { try { paramValue = XmlConvert.ToBoolean(value); } catch (FormatException e) { throw new ArgumentException(Strings.InvalidBooleanParameterValue(value, parameterName), e); } } else { throw new ArgumentException(Strings.ParameterSpecifiedMultipleTimes(UseCollectionParameterName)); } } ////// Validate the version parameter value is valid. /// /// version parameter value as specified in the .svcmap file. ///instance of DataServiceCodeVersion, which contains the value of the version parameter as specified in the svcmap file. private static void ValidateVersionParameter(ref DataServiceCodeVersion? version, string parameterValue) { if (version == null) { if (parameterValue == Version1Dot0) { version = DataServiceCodeVersion.V1; } else if (parameterValue == Version2Dot0) { version = DataServiceCodeVersion.V2; } else { throw new ArgumentException( Strings.InvalidVersionParameterValue( parameterValue, VersionParameterName, String.Format(CultureInfo.InvariantCulture, "'{0}', '{1}'", Version1Dot0, Version2Dot0))); } } else { throw new ArgumentException(Strings.ParameterSpecifiedMultipleTimes(VersionParameterName)); } } } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- Rotation3D.cs
- PropertyTabChangedEvent.cs
- DbSourceCommand.cs
- DrawingGroup.cs
- InheritanceRules.cs
- PackUriHelper.cs
- DBPropSet.cs
- CalendarAutomationPeer.cs
- Number.cs
- ViewStateException.cs
- RichTextBoxConstants.cs
- TerminatorSinks.cs
- XXXOnTypeBuilderInstantiation.cs
- ArraySortHelper.cs
- XmlSchemaGroup.cs
- MenuEventArgs.cs
- OperatingSystem.cs
- ExceptionHelpers.cs
- SoapSchemaMember.cs
- Unit.cs
- TransactionFlowElement.cs
- HtmlShimManager.cs
- ThreadSafeList.cs
- Serializer.cs
- ServiceOperation.cs
- ConnectivityStatus.cs
- MobileDeviceCapabilitiesSectionHandler.cs
- _ConnectOverlappedAsyncResult.cs
- WorkflowServiceHostFactory.cs
- SoundPlayer.cs
- UIElementHelper.cs
- DeferredReference.cs
- WebServiceErrorEvent.cs
- DigestTraceRecordHelper.cs
- HistoryEventArgs.cs
- ProtocolImporter.cs
- Panel.cs
- DataServiceConfiguration.cs
- CreateUserWizard.cs
- OledbConnectionStringbuilder.cs
- KeyConstraint.cs
- SortedList.cs
- FormatterConverter.cs
- DataControlPagerLinkButton.cs
- ContourSegment.cs
- SqlUtils.cs
- ChameleonKey.cs
- SettingsAttributes.cs
- WebPartEditVerb.cs
- XmlSchemaValidator.cs
- WebPartConnectVerb.cs
- ListViewContainer.cs
- ChannelTraceRecord.cs
- wgx_commands.cs
- DataTableMappingCollection.cs
- Utility.cs
- EventListener.cs
- ToolStripItemImageRenderEventArgs.cs
- XhtmlBasicTextViewAdapter.cs
- ZipIOCentralDirectoryBlock.cs
- Clause.cs
- DataGridBeginningEditEventArgs.cs
- ComponentDispatcherThread.cs
- COM2PropertyDescriptor.cs
- IgnoreSectionHandler.cs
- QilVisitor.cs
- DataFormats.cs
- MenuItem.cs
- ListViewTableRow.cs
- FragmentNavigationEventArgs.cs
- ConfigurationPropertyAttribute.cs
- PtsCache.cs
- EventData.cs
- WsatConfiguration.cs
- DataGridViewCellConverter.cs
- HotSpotCollectionEditor.cs
- DocumentViewerBaseAutomationPeer.cs
- OverflowException.cs
- ResourceSet.cs
- WizardStepBase.cs
- DesignerContextDescriptor.cs
- DocumentPage.cs
- WindowPattern.cs
- OpacityConverter.cs
- LinqDataSourceHelper.cs
- TrustExchangeException.cs
- DescendantBaseQuery.cs
- WindowsMenu.cs
- httpserverutility.cs
- TypeSystemProvider.cs
- Border.cs
- NativeRightsManagementAPIsStructures.cs
- StringHandle.cs
- DateTimeUtil.cs
- Brush.cs
- BitmapEffectOutputConnector.cs
- OrderedDictionary.cs
- DataGridViewTextBoxCell.cs
- HttpDigestClientCredential.cs
- LoadRetryHandler.cs