1 // 2 // System.Web.Compilation.AppCodeCompiler: A compiler for the App_Code folder 3 // 4 // Authors: 5 // Marek Habersack (grendello@gmail.com) 6 // 7 // (C) 2006 Marek Habersack 8 // 9 10 // 11 // Permission is hereby granted, free of charge, to any person obtaining 12 // a copy of this software and associated documentation files (the 13 // "Software"), to deal in the Software without restriction, including 14 // without limitation the rights to use, copy, modify, merge, publish, 15 // distribute, sublicense, and/or sell copies of the Software, and to 16 // permit persons to whom the Software is furnished to do so, subject to 17 // the following conditions: 18 // 19 // The above copyright notice and this permission notice shall be 20 // included in all copies or substantial portions of the Software. 21 // 22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 29 // 30 31 using System; 32 using System.CodeDom; 33 using System.CodeDom.Compiler; 34 using System.Configuration; 35 using System.Collections; 36 using System.Collections.Generic; 37 using System.Collections.Specialized; 38 using System.Globalization; 39 using System.IO; 40 using System.Reflection; 41 using System.Web; 42 using System.Web.Configuration; 43 using System.Web.Profile; 44 using System.Web.Util; 45 46 namespace System.Web.Compilation 47 { 48 class AssemblyPathResolver 49 { 50 static Dictionary <string, string> assemblyCache; 51 AssemblyPathResolver()52 static AssemblyPathResolver () 53 { 54 assemblyCache = new Dictionary <string, string> (); 55 } 56 GetAssemblyPath(string assemblyName)57 public static string GetAssemblyPath (string assemblyName) 58 { 59 lock (assemblyCache) { 60 if (assemblyCache.ContainsKey (assemblyName)) 61 return assemblyCache [assemblyName]; 62 63 Assembly asm = null; 64 Exception error = null; 65 if (assemblyName.IndexOf (',') != -1) { 66 try { 67 asm = Assembly.Load (assemblyName); 68 } catch (Exception e) { 69 error = e; 70 } 71 } 72 73 if (asm == null) { 74 try { 75 asm = Assembly.LoadWithPartialName (assemblyName); 76 } catch (Exception e) { 77 error = e; 78 } 79 } 80 81 if (asm == null) 82 throw new HttpException (String.Format ("Unable to find assembly {0}", assemblyName), error); 83 84 string path = new Uri (asm.CodeBase).LocalPath; 85 assemblyCache.Add (assemblyName, path); 86 return path; 87 } 88 } 89 } 90 91 internal class AppCodeAssembly 92 { 93 List<string> files; 94 List<CodeCompileUnit> units; 95 96 string name; 97 string path; 98 bool validAssembly; 99 string outputAssemblyName; 100 101 public string OutputAssemblyName 102 { 103 get { 104 return outputAssemblyName; 105 } 106 } 107 108 public bool IsValid 109 { 110 get { return validAssembly; } 111 } 112 113 public string SourcePath 114 { 115 get { return path; } 116 } 117 118 // temporary 119 public string Name 120 { 121 get { return name; } 122 } 123 124 public List<string> Files 125 { 126 get { return files; } 127 } 128 // temporary 129 AppCodeAssembly(string name, string path)130 public AppCodeAssembly (string name, string path) 131 { 132 this.files = new List<string> (); 133 this.units = new List<CodeCompileUnit> (); 134 this.validAssembly = true; 135 this.name = name; 136 this.path = path; 137 } 138 AddFile(string path)139 public void AddFile (string path) 140 { 141 files.Add (path); 142 } 143 AddUnit(CodeCompileUnit unit)144 public void AddUnit (CodeCompileUnit unit) 145 { 146 units.Add (unit); 147 } 148 OnCreateTemporaryAssemblyFile(string path)149 object OnCreateTemporaryAssemblyFile (string path) 150 { 151 FileStream f = new FileStream (path, FileMode.CreateNew); 152 f.Close (); 153 return path; 154 } 155 156 // Build and add the assembly to the BuildManager's 157 // CodeAssemblies collection Build(string[] binAssemblies)158 public void Build (string[] binAssemblies) 159 { 160 Type compilerProvider = null; 161 CompilerInfo compilerInfo = null, cit; 162 string extension, language, cpfile = null; 163 List<string> knownfiles = new List<string>(); 164 List<string> unknownfiles = new List<string>(); 165 166 // First make sure all the files are in the same 167 // language 168 bool known = false; 169 foreach (string f in files) { 170 known = true; 171 language = null; 172 173 extension = Path.GetExtension (f); 174 if (String.IsNullOrEmpty (extension) || !CodeDomProvider.IsDefinedExtension (extension)) 175 known = false; 176 if (known) { 177 language = CodeDomProvider.GetLanguageFromExtension(extension); 178 if (!CodeDomProvider.IsDefinedLanguage (language)) 179 known = false; 180 } 181 if (!known || language == null) { 182 unknownfiles.Add (f); 183 continue; 184 } 185 186 cit = CodeDomProvider.GetCompilerInfo (language); 187 if (cit == null || !cit.IsCodeDomProviderTypeValid) 188 continue; 189 if (compilerProvider == null) { 190 cpfile = f; 191 compilerProvider = cit.CodeDomProviderType; 192 compilerInfo = cit; 193 } else if (compilerProvider != cit.CodeDomProviderType) 194 throw new HttpException ( 195 String.Format ( 196 "Files {0} and {1} are in different languages - they cannot be compiled into the same assembly", 197 Path.GetFileName (cpfile), 198 Path.GetFileName (f))); 199 knownfiles.Add (f); 200 } 201 202 CodeDomProvider provider = null; 203 CompilationSection compilationSection = WebConfigurationManager.GetWebApplicationSection ("system.web/compilation") as CompilationSection; 204 if (compilerInfo == null) { 205 if (!CodeDomProvider.IsDefinedLanguage (compilationSection.DefaultLanguage)) 206 throw new HttpException ("Failed to retrieve default source language"); 207 compilerInfo = CodeDomProvider.GetCompilerInfo (compilationSection.DefaultLanguage); 208 if (compilerInfo == null || !compilerInfo.IsCodeDomProviderTypeValid) 209 throw new HttpException ("Internal error while initializing application"); 210 } 211 212 provider = compilerInfo.CreateProvider (); 213 if (provider == null) 214 throw new HttpException ("A code provider error occurred while initializing application."); 215 216 AssemblyBuilder abuilder = new AssemblyBuilder (provider); 217 foreach (string file in knownfiles) 218 abuilder.AddCodeFile (file); 219 foreach (CodeCompileUnit unit in units) 220 abuilder.AddCodeCompileUnit (unit); 221 222 BuildProvider bprovider; 223 CompilerParameters parameters = compilerInfo.CreateDefaultCompilerParameters (); 224 parameters.IncludeDebugInformation = compilationSection.Debug; 225 226 if (binAssemblies != null && binAssemblies.Length > 0) { 227 StringCollection parmRefAsm = parameters.ReferencedAssemblies; 228 foreach (string binAsm in binAssemblies) { 229 if (parmRefAsm.Contains (binAsm)) 230 continue; 231 232 parmRefAsm.Add (binAsm); 233 } 234 } 235 236 if (compilationSection != null) { 237 foreach (AssemblyInfo ai in compilationSection.Assemblies) 238 if (ai.Assembly != "*") { 239 try { 240 parameters.ReferencedAssemblies.Add ( 241 AssemblyPathResolver.GetAssemblyPath (ai.Assembly)); 242 } catch (Exception ex) { 243 throw new HttpException ( 244 String.Format ("Could not find assembly {0}.", ai.Assembly), 245 ex); 246 } 247 } 248 249 BuildProviderCollection buildProviders = compilationSection.BuildProviders; 250 251 foreach (string file in unknownfiles) { 252 bprovider = GetBuildProviderFor (file, buildProviders); 253 if (bprovider == null) 254 continue; 255 bprovider.GenerateCode (abuilder); 256 } 257 } 258 259 if (knownfiles.Count == 0 && unknownfiles.Count == 0 && units.Count == 0) 260 return; 261 262 outputAssemblyName = (string)FileUtils.CreateTemporaryFile ( 263 AppDomain.CurrentDomain.SetupInformation.DynamicBase, 264 name, "dll", OnCreateTemporaryAssemblyFile); 265 parameters.OutputAssembly = outputAssemblyName; 266 foreach (Assembly a in BuildManager.TopLevelAssemblies) 267 parameters.ReferencedAssemblies.Add (a.Location); 268 CompilerResults results = abuilder.BuildAssembly (parameters); 269 if (results == null) 270 return; 271 272 if (results.NativeCompilerReturnValue == 0) { 273 BuildManager.CodeAssemblies.Add (results.CompiledAssembly); 274 BuildManager.TopLevelAssemblies.Add (results.CompiledAssembly); 275 HttpRuntime.WritePreservationFile (results.CompiledAssembly, name); 276 } else { 277 if (HttpContext.Current.IsCustomErrorEnabled) 278 throw new HttpException ("An error occurred while initializing application."); 279 throw new CompilationException (null, results.Errors, null); 280 } 281 } 282 PhysicalToVirtual(string file)283 VirtualPath PhysicalToVirtual (string file) 284 { 285 return new VirtualPath (file.Replace (HttpRuntime.AppDomainAppPath, "~/").Replace (Path.DirectorySeparatorChar, '/')); 286 } 287 GetBuildProviderFor(string file, BuildProviderCollection buildProviders)288 BuildProvider GetBuildProviderFor (string file, BuildProviderCollection buildProviders) 289 { 290 if (file == null || file.Length == 0 || buildProviders == null || buildProviders.Count == 0) 291 return null; 292 293 BuildProvider ret = buildProviders.GetProviderInstanceForExtension (Path.GetExtension (file)); 294 if (ret != null && IsCorrectBuilderType (ret)) { 295 ret.SetVirtualPath (PhysicalToVirtual (file)); 296 return ret; 297 } 298 299 return null; 300 } 301 IsCorrectBuilderType(BuildProvider bp)302 bool IsCorrectBuilderType (BuildProvider bp) 303 { 304 if (bp == null) 305 return false; 306 Type type; 307 object[] attrs; 308 309 type = bp.GetType (); 310 attrs = type.GetCustomAttributes (true); 311 if (attrs == null) 312 return false; 313 314 BuildProviderAppliesToAttribute bpAppliesTo; 315 bool attributeFound = false; 316 foreach (object attr in attrs) { 317 bpAppliesTo = attr as BuildProviderAppliesToAttribute; 318 if (bpAppliesTo == null) 319 continue; 320 attributeFound = true; 321 if ((bpAppliesTo.AppliesTo & BuildProviderAppliesTo.All) == BuildProviderAppliesTo.All || 322 (bpAppliesTo.AppliesTo & BuildProviderAppliesTo.Code) == BuildProviderAppliesTo.Code) 323 return true; 324 } 325 326 if (attributeFound) 327 return false; 328 return true; 329 } 330 331 } 332 333 internal class AppCodeCompiler 334 { 335 static bool _alreadyCompiled; 336 internal static string DefaultAppCodeAssemblyName; 337 338 // A dictionary that contains an entry per an assembly that will 339 // be produced by compiling App_Code. There's one main assembly 340 // and an optional number of assemblies as defined by the 341 // codeSubDirectories sub-element of the compilation element in 342 // the system.web section of the app's config file. 343 // Each entry's value is an AppCodeAssembly instance. 344 // 345 // Assemblies are named as follows: 346 // 347 // 1. main assembly: App_Code.{HASH} 348 // 2. subdir assemblies: App_SubCode_{DirName}.{HASH} 349 // 350 // If any of the assemblies contains files that would be 351 // compiled with different compilers, a System.Web.HttpException 352 // is thrown. 353 // 354 // Files for which there is no explicit builder are ignored 355 // silently 356 // 357 // Files for which exist BuildProviders but which have no 358 // unambiguous language assigned to them (e.g. .wsdl files), are 359 // built using the default website compiler. 360 List<AppCodeAssembly> assemblies; 361 string providerTypeName = null; 362 AppCodeCompiler()363 public AppCodeCompiler () 364 { 365 assemblies = new List<AppCodeAssembly>(); 366 } 367 ProcessAppCodeDir(string appCode, AppCodeAssembly defasm)368 bool ProcessAppCodeDir (string appCode, AppCodeAssembly defasm) 369 { 370 // First process the codeSubDirectories 371 CompilationSection cs = (CompilationSection) WebConfigurationManager.GetWebApplicationSection ("system.web/compilation"); 372 373 if (cs != null) { 374 string aname; 375 for (int i = 0; i < cs.CodeSubDirectories.Count; i++) { 376 aname = String.Concat ("App_SubCode_", cs.CodeSubDirectories[i].DirectoryName); 377 assemblies.Add (new AppCodeAssembly ( 378 aname, 379 Path.Combine (appCode, cs.CodeSubDirectories[i].DirectoryName))); 380 } 381 } 382 383 return CollectFiles (appCode, defasm); 384 } 385 GetProfilePropertyType(string type)386 CodeTypeReference GetProfilePropertyType (string type) 387 { 388 if (String.IsNullOrEmpty (type)) 389 throw new ArgumentException ("String size cannot be 0", "type"); 390 return new CodeTypeReference (type); 391 } 392 FindProviderTypeName(ProfileSection ps, string providerName)393 string FindProviderTypeName (ProfileSection ps, string providerName) 394 { 395 if (ps.Providers == null || ps.Providers.Count == 0) 396 return null; 397 398 ProviderSettings pset = ps.Providers [providerName]; 399 if (pset == null) 400 return null; 401 return pset.Type; 402 } 403 GetProfileProviderAttribute(ProfileSection ps, CodeAttributeDeclarationCollection collection, string providerName)404 void GetProfileProviderAttribute (ProfileSection ps, CodeAttributeDeclarationCollection collection, 405 string providerName) 406 { 407 if (String.IsNullOrEmpty (providerName)) 408 providerTypeName = FindProviderTypeName (ps, ps.DefaultProvider); 409 else 410 providerTypeName = FindProviderTypeName (ps, providerName); 411 if (providerTypeName == null) 412 throw new HttpException (String.Format ("Profile provider type not defined: {0}", 413 providerName)); 414 415 collection.Add ( 416 new CodeAttributeDeclaration ( 417 "ProfileProvider", 418 new CodeAttributeArgument ( 419 new CodePrimitiveExpression (providerTypeName) 420 ) 421 ) 422 ); 423 } 424 GetProfileSettingsSerializeAsAttribute(ProfileSection ps, CodeAttributeDeclarationCollection collection, SerializationMode mode)425 void GetProfileSettingsSerializeAsAttribute (ProfileSection ps, CodeAttributeDeclarationCollection collection, 426 SerializationMode mode) 427 { 428 string parameter = String.Concat ("SettingsSerializeAs.", mode.ToString ()); 429 collection.Add ( 430 new CodeAttributeDeclaration ( 431 "SettingsSerializeAs", 432 new CodeAttributeArgument ( 433 new CodeSnippetExpression (parameter) 434 ) 435 ) 436 ); 437 438 } 439 AddProfileClassGetProfileMethod(CodeTypeDeclaration profileClass)440 void AddProfileClassGetProfileMethod (CodeTypeDeclaration profileClass) 441 { 442 CodeMethodReferenceExpression mref = new CodeMethodReferenceExpression ( 443 new CodeTypeReferenceExpression (typeof (System.Web.Profile.ProfileBase)), 444 "Create"); 445 CodeMethodInvokeExpression minvoke = new CodeMethodInvokeExpression ( 446 mref, 447 new CodeExpression[] { new CodeVariableReferenceExpression ("username") } 448 ); 449 CodeCastExpression cast = new CodeCastExpression (); 450 cast.TargetType = new CodeTypeReference ("ProfileCommon"); 451 cast.Expression = minvoke; 452 453 CodeMethodReturnStatement ret = new CodeMethodReturnStatement (); 454 ret.Expression = cast; 455 456 CodeMemberMethod method = new CodeMemberMethod (); 457 method.Name = "GetProfile"; 458 method.ReturnType = new CodeTypeReference ("ProfileCommon"); 459 method.Parameters.Add (new CodeParameterDeclarationExpression("System.String", "username")); 460 method.Statements.Add (ret); 461 method.Attributes = MemberAttributes.Public; 462 463 profileClass.Members.Add (method); 464 } 465 AddProfileClassProperty(ProfileSection ps, CodeTypeDeclaration profileClass, ProfilePropertySettings pset)466 void AddProfileClassProperty (ProfileSection ps, CodeTypeDeclaration profileClass, ProfilePropertySettings pset) 467 { 468 string name = pset.Name; 469 if (String.IsNullOrEmpty (name)) 470 throw new HttpException ("Profile property 'Name' attribute cannot be null."); 471 CodeMemberProperty property = new CodeMemberProperty (); 472 string typeName = pset.Type; 473 if (typeName == "string") 474 typeName = "System.String"; 475 property.Name = name; 476 property.Type = GetProfilePropertyType (typeName); 477 property.Attributes = MemberAttributes.Public; 478 479 CodeAttributeDeclarationCollection collection = new CodeAttributeDeclarationCollection(); 480 GetProfileProviderAttribute (ps, collection, pset.Provider); 481 GetProfileSettingsSerializeAsAttribute (ps, collection, pset.SerializeAs); 482 483 property.CustomAttributes = collection; 484 CodeMethodReturnStatement ret = new CodeMethodReturnStatement (); 485 CodeCastExpression cast = new CodeCastExpression (); 486 ret.Expression = cast; 487 488 CodeMethodReferenceExpression mref = new CodeMethodReferenceExpression ( 489 new CodeThisReferenceExpression (), 490 "GetPropertyValue"); 491 CodeMethodInvokeExpression minvoke = new CodeMethodInvokeExpression ( 492 mref, 493 new CodeExpression[] { new CodePrimitiveExpression (name) } 494 ); 495 cast.TargetType = new CodeTypeReference (typeName); 496 cast.Expression = minvoke; 497 property.GetStatements.Add (ret); 498 499 if (!pset.ReadOnly) { 500 mref = new CodeMethodReferenceExpression ( 501 new CodeThisReferenceExpression (), 502 "SetPropertyValue"); 503 minvoke = new CodeMethodInvokeExpression ( 504 mref, 505 new CodeExpression[] { new CodePrimitiveExpression (name), new CodeSnippetExpression ("value") } 506 ); 507 property.SetStatements.Add (minvoke); 508 } 509 510 511 profileClass.Members.Add (property); 512 } 513 AddProfileClassGroupProperty(string groupName, string memberName, CodeTypeDeclaration profileClass)514 void AddProfileClassGroupProperty (string groupName, string memberName, CodeTypeDeclaration profileClass) 515 { 516 CodeMemberProperty property = new CodeMemberProperty (); 517 property.Name = memberName; 518 property.Type = new CodeTypeReference (groupName); 519 property.Attributes = MemberAttributes.Public; 520 521 CodeMethodReturnStatement ret = new CodeMethodReturnStatement (); 522 CodeCastExpression cast = new CodeCastExpression (); 523 ret.Expression = cast; 524 525 CodeMethodReferenceExpression mref = new CodeMethodReferenceExpression ( 526 new CodeThisReferenceExpression (), 527 "GetProfileGroup"); 528 CodeMethodInvokeExpression minvoke = new CodeMethodInvokeExpression ( 529 mref, 530 new CodeExpression[] { new CodePrimitiveExpression (memberName) } 531 ); 532 cast.TargetType = new CodeTypeReference (groupName); 533 cast.Expression = minvoke; 534 property.GetStatements.Add (ret); 535 536 profileClass.Members.Add (property); 537 } 538 BuildProfileClass(ProfileSection ps, string className, ProfilePropertySettingsCollection psc, CodeNamespace ns, string baseClass, bool baseIsGlobal, SortedList <string, string> groupProperties)539 void BuildProfileClass (ProfileSection ps, string className, ProfilePropertySettingsCollection psc, 540 CodeNamespace ns, string baseClass, bool baseIsGlobal, 541 SortedList <string, string> groupProperties) 542 { 543 CodeTypeDeclaration profileClass = new CodeTypeDeclaration (className); 544 CodeTypeReference cref = new CodeTypeReference (baseClass); 545 if (baseIsGlobal) 546 cref.Options |= CodeTypeReferenceOptions.GlobalReference; 547 profileClass.BaseTypes.Add (cref); 548 profileClass.TypeAttributes = TypeAttributes.Public; 549 ns.Types.Add (profileClass); 550 551 foreach (ProfilePropertySettings pset in psc) 552 AddProfileClassProperty (ps, profileClass, pset); 553 if (groupProperties != null && groupProperties.Count > 0) 554 foreach (KeyValuePair <string, string> group in groupProperties) 555 AddProfileClassGroupProperty (group.Key, group.Value, profileClass); 556 AddProfileClassGetProfileMethod (profileClass); 557 } 558 MakeGroupName(string name)559 string MakeGroupName (string name) 560 { 561 return String.Concat ("ProfileGroup", name); 562 } 563 564 // FIXME: there should be some validation of syntactic correctness of the member/class name 565 // for the groups/properties. For now it's left to the compiler to report errors. 566 // 567 // CodeGenerator.IsValidLanguageIndependentIdentifier (id) - use that 568 // ProcessCustomProfile(ProfileSection ps, AppCodeAssembly defasm)569 bool ProcessCustomProfile (ProfileSection ps, AppCodeAssembly defasm) 570 { 571 CodeCompileUnit unit = new CodeCompileUnit (); 572 CodeNamespace ns = new CodeNamespace (null); 573 unit.Namespaces.Add (ns); 574 defasm.AddUnit (unit); 575 576 ns.Imports.Add (new CodeNamespaceImport ("System")); 577 ns.Imports.Add (new CodeNamespaceImport ("System.Configuration")); 578 ns.Imports.Add (new CodeNamespaceImport ("System.Web")); 579 ns.Imports.Add (new CodeNamespaceImport ("System.Web.Profile")); 580 581 RootProfilePropertySettingsCollection props = ps.PropertySettings; 582 if (props == null) 583 return true; 584 585 SortedList<string, string> groupProperties = new SortedList<string, string> (); 586 string groupName; 587 foreach (ProfileGroupSettings pgs in props.GroupSettings) { 588 groupName = MakeGroupName (pgs.Name); 589 groupProperties.Add (groupName, pgs.Name); 590 BuildProfileClass (ps, groupName, pgs.PropertySettings, ns, 591 "System.Web.Profile.ProfileGroupBase", true, null); 592 } 593 594 string baseType = ps.Inherits; 595 if (String.IsNullOrEmpty (baseType)) 596 baseType = "System.Web.Profile.ProfileBase"; 597 else { 598 string[] parts = baseType.Split (new char[] {','}); 599 if (parts.Length > 1) 600 baseType = parts [0].Trim (); 601 } 602 603 bool baseIsGlobal; 604 if (baseType.IndexOf ('.') != -1) 605 baseIsGlobal = true; 606 else 607 baseIsGlobal = false; 608 609 BuildProfileClass (ps, "ProfileCommon", props, ns, baseType, baseIsGlobal, groupProperties); 610 return true; 611 } 612 613 // void PutCustomProfileInContext (HttpContext context, string assemblyName) 614 // { 615 // Type type = Type.GetType (String.Format ("ProfileCommon, {0}", 616 // Path.GetFileNameWithoutExtension (assemblyName))); 617 // ProfileBase pb = Activator.CreateInstance (type) as ProfileBase; 618 // if (pb != null) 619 // context.Profile = pb; 620 // } 621 HaveCustomProfile(ProfileSection ps)622 public static bool HaveCustomProfile (ProfileSection ps) 623 { 624 if (ps == null || !ps.Enabled) 625 return false; 626 627 RootProfilePropertySettingsCollection props = ps.PropertySettings; 628 ProfileGroupSettingsCollection groups = props != null ? props.GroupSettings : null; 629 630 if (!String.IsNullOrEmpty (ps.Inherits) || (props != null && props.Count > 0) || (groups != null && groups.Count > 0)) 631 return true; 632 633 return false; 634 } 635 Compile()636 public void Compile () 637 { 638 if (_alreadyCompiled) 639 return; 640 641 string appCode = Path.Combine (HttpRuntime.AppDomainAppPath, "App_Code"); 642 ProfileSection ps = WebConfigurationManager.GetWebApplicationSection ("system.web/profile") as ProfileSection; 643 bool haveAppCodeDir = Directory.Exists (appCode); 644 bool haveCustomProfile = HaveCustomProfile (ps); 645 646 if (!haveAppCodeDir && !haveCustomProfile) 647 return; 648 649 AppCodeAssembly defasm = new AppCodeAssembly ("App_Code", appCode); 650 assemblies.Add (defasm); 651 652 bool haveCode = false; 653 if (haveAppCodeDir) 654 haveCode = ProcessAppCodeDir (appCode, defasm); 655 if (haveCustomProfile) 656 if (ProcessCustomProfile (ps, defasm)) 657 haveCode = true; 658 659 if (!haveCode) 660 return; 661 662 HttpRuntime.EnableAssemblyMapping (true); 663 string[] binAssemblies = HttpApplication.BinDirectoryAssemblies; 664 665 foreach (AppCodeAssembly aca in assemblies) 666 aca.Build (binAssemblies); 667 _alreadyCompiled = true; 668 DefaultAppCodeAssemblyName = Path.GetFileNameWithoutExtension (defasm.OutputAssemblyName); 669 670 RunAppInitialize (); 671 672 if (haveCustomProfile && providerTypeName != null) { 673 if (Type.GetType (providerTypeName, false) == null) { 674 foreach (Assembly asm in BuildManager.TopLevelAssemblies) { 675 if (asm == null) 676 continue; 677 678 if (asm.GetType (providerTypeName, false) != null) 679 return; 680 } 681 } else 682 return; 683 684 Exception noTypeException = null; 685 Type ptype = null; 686 687 try { 688 ptype = HttpApplication.LoadTypeFromBin (providerTypeName); 689 } catch (Exception ex) { 690 noTypeException = ex; 691 } 692 693 if (ptype == null) 694 throw new HttpException (String.Format ("Profile provider type not found: {0}", providerTypeName), noTypeException); 695 } 696 } 697 698 // Documented (sort of...) briefly in: 699 // 700 // http://quickstarts.asp.net/QuickStartv20/aspnet/doc/extensibility.aspx 701 // http://msdn2.microsoft.com/en-us/library/system.web.hosting.virtualpathprovider.aspx RunAppInitialize()702 void RunAppInitialize () 703 { 704 MethodInfo mi = null, tmi; 705 Type[] types; 706 707 foreach (Assembly asm in BuildManager.CodeAssemblies) { 708 types = asm.GetExportedTypes (); 709 if (types == null || types.Length == 0) 710 continue; 711 712 foreach (Type type in types) { 713 tmi = type.GetMethod ("AppInitialize", 714 BindingFlags.Public | BindingFlags.Static | BindingFlags.IgnoreCase, 715 null, 716 Type.EmptyTypes, 717 null); 718 if (tmi == null) 719 continue; 720 721 if (mi != null) 722 throw new HttpException ("The static AppInitialize method found in more than one type in the App_Code directory."); 723 724 mi = tmi; 725 } 726 } 727 728 if (mi == null) 729 return; 730 731 mi.Invoke (null, null); 732 } 733 CollectFiles(string dir, AppCodeAssembly aca)734 bool CollectFiles (string dir, AppCodeAssembly aca) 735 { 736 bool haveFiles = false; 737 738 AppCodeAssembly curaca = aca; 739 foreach (string f in Directory.GetFiles (dir)) { 740 aca.AddFile (f); 741 haveFiles = true; 742 } 743 744 foreach (string d in Directory.GetDirectories (dir)) { 745 foreach (AppCodeAssembly a in assemblies) 746 if (a.SourcePath == d) { 747 curaca = a; 748 break; 749 } 750 if (CollectFiles (d, curaca)) 751 haveFiles = true; 752 curaca = aca; 753 } 754 return haveFiles; 755 } 756 } 757 } 758 759