1 //------------------------------------------------------------------------------
2 // <copyright file="WebReferencesBuildProvider.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 //------------------------------------------------------------------------------
6 
7 namespace System.Web.Compilation {
8 
9 using System;
10 using System.Globalization;
11 using System.CodeDom;
12 using System.CodeDom.Compiler;
13 using System.Collections.Specialized;
14 using System.Net;
15 using System.Xml.Serialization;
16 #if !FEATURE_PAL
17 using System.Web.Services.Description;
18 using System.Web.Services.Discovery;
19 #endif // !FEATURE_PAL
20 using System.Web.Hosting;
21 using System.Web.UI;
22 using System.Web.Util;
23 using Util=System.Web.UI.Util;
24 
25 internal class WebReferencesBuildProvider: BuildProvider {
26 
27     private VirtualDirectory _vdir;
28 
29     private const string IndigoWebRefProviderTypeName = "System.Web.Compilation.WCFBuildProvider";
30     private static Type s_indigoWebRefProviderType;
31     private static bool s_triedToGetWebRefType;
32 
WebReferencesBuildProvider(VirtualDirectory vdir)33     internal WebReferencesBuildProvider(VirtualDirectory vdir) {
34         _vdir = vdir;
35     }
36 
GenerateCode(AssemblyBuilder assemblyBuilder)37     public override void GenerateCode(AssemblyBuilder assemblyBuilder)  {
38 
39         // Only attempt to get the Indigo provider once
40         if (!s_triedToGetWebRefType) {
41             s_indigoWebRefProviderType = BuildManager.GetType(IndigoWebRefProviderTypeName, false /*throwOnError*/);
42             s_triedToGetWebRefType = true;
43         }
44 
45         // If we have an Indigo provider, instantiate it and forward the GenerateCode call to it
46         if (s_indigoWebRefProviderType != null) {
47             BuildProvider buildProvider = (BuildProvider)HttpRuntime.CreateNonPublicInstance(s_indigoWebRefProviderType);
48             buildProvider.SetVirtualPath(VirtualPathObject);
49             buildProvider.GenerateCode(assemblyBuilder);
50         }
51 
52         // e.g "/MyApp/Application_WebReferences"
53         VirtualPath rootWebRefDirVirtualPath = HttpRuntime.WebRefDirectoryVirtualPath;
54 
55         // e.g "/MyApp/Application_WebReferences/Foo/Bar"
56         string currentWebRefDirVirtualPath = _vdir.VirtualPath;
57 
58         Debug.Assert(StringUtil.StringStartsWithIgnoreCase(
59             currentWebRefDirVirtualPath, rootWebRefDirVirtualPath.VirtualPathString));
60 
61         string ns;
62 
63         if (rootWebRefDirVirtualPath.VirtualPathString.Length == currentWebRefDirVirtualPath.Length) {
64             // If it's the root WebReferences dir, use the empty namespace
65             ns = String.Empty;
66         }
67         else {
68             // e.g. "Foo/Bar"
69             Debug.Assert(rootWebRefDirVirtualPath.HasTrailingSlash);
70             currentWebRefDirVirtualPath = UrlPath.RemoveSlashFromPathIfNeeded(currentWebRefDirVirtualPath);
71             currentWebRefDirVirtualPath = currentWebRefDirVirtualPath.Substring(
72                 rootWebRefDirVirtualPath.VirtualPathString.Length);
73 
74             // Split it into chunks separated by '/'
75             string[] chunks = currentWebRefDirVirtualPath.Split('/');
76 
77             // Turn all the relevant chunks into valid namespace chunks
78             for (int i=0; i<chunks.Length; i++) {
79                 chunks[i] = Util.MakeValidTypeNameFromString(chunks[i]);
80             }
81 
82             // Put the relevant chunks back together to form the namespace
83             ns = String.Join(".", chunks);
84         }
85 #if !FEATURE_PAL // FEATURE_PAL does not support System.Web.Services
86 
87         CodeNamespace codeNamespace = new CodeNamespace(ns);
88 
89         // for each discomap file, read all references and add them to the WebReferenceCollection
90         WebReferenceCollection webs = new WebReferenceCollection();
91 
92         bool hasDiscomap = false;
93 
94         // Go through all the discomap in the directory
95         foreach (VirtualFile child in _vdir.Files) {
96 
97             string extension = UrlPath.GetExtension(child.VirtualPath);
98             extension = extension.ToLower(CultureInfo.InvariantCulture);
99 
100             if (extension == ".discomap") {
101                 // NOTE: the WebReferences code requires physical path, so this feature
102                 // cannot work with a non-file based VirtualPathProvider
103                 string physicalPath = HostingEnvironment.MapPath(child.VirtualPath);
104 
105                 DiscoveryClientProtocol client = new DiscoveryClientProtocol();
106                 client.AllowAutoRedirect = true;
107                 client.Credentials = CredentialCache.DefaultCredentials;
108 
109                 client.ReadAll(physicalPath);
110 
111                 WebReference webRefTemp = new WebReference(client.Documents, codeNamespace);
112 
113                 //
114 
115                 string fileName = System.IO.Path.ChangeExtension(UrlPath.GetFileName(child.VirtualPath), null);
116                 string appSetttingUrlKey = ns + "." + fileName;
117 
118                 WebReference web = new WebReference(client.Documents, codeNamespace, webRefTemp.ProtocolName, appSetttingUrlKey, null);
119 
120                 webs.Add(web);
121 
122                 hasDiscomap = true;
123             }
124         }
125 
126         // If we didn't find any discomap files, we have nothing to generate
127         if (!hasDiscomap)
128             return;
129 
130         CodeCompileUnit codeCompileUnit = new CodeCompileUnit();
131         codeCompileUnit.Namespaces.Add(codeNamespace);
132 
133         //public static StringCollection GenerateWebReferences(WebReferenceCollection webReferences, CodeDomProvider codeProvider, CodeCompileUnit codeCompileUnit, WebReferenceOptions options) {
134         WebReferenceOptions options = new WebReferenceOptions();
135         options.CodeGenerationOptions = CodeGenerationOptions.GenerateProperties | CodeGenerationOptions.GenerateNewAsync | CodeGenerationOptions.GenerateOldAsync;
136         options.Style = ServiceDescriptionImportStyle.Client;
137         options.Verbose = true;
138         StringCollection shareWarnings = ServiceDescriptionImporter.GenerateWebReferences(webs, assemblyBuilder.CodeDomProvider, codeCompileUnit, options);
139         // Add the CodeCompileUnit to the compilation
140         assemblyBuilder.AddCodeCompileUnit(this, codeCompileUnit);
141 #else // !FEATURE_PAL
142         return;
143 #endif // !FEATURE_PAL
144     }
145 }
146 
147 }
148