File: System\Xaml\Hosting\XamlBuildProvider.cs
Project: ndp\cdf\src\NetFx40\System.Xaml.Hosting\System.Xaml.Hosting.csproj (System.Xaml.Hosting)
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
//------------------------------------------------------------
 
namespace System.Xaml.Hosting
{
    using System;
    using System.CodeDom.Compiler;
    using System.Collections.Generic;
    using System.Configuration;
    using System.Diagnostics.CodeAnalysis;
    using System.IO;
    using System.Reflection;
    using System.Runtime;
    using System.Text;
    using System.Web;
    using System.Web.Compilation;
    using System.Web.Hosting;
    using System.Xaml;
    using System.Xaml.Hosting.Configuration;
    using System.Xml;   
 
    [BuildProviderAppliesTo(BuildProviderAppliesTo.Web)]
    public class XamlBuildProvider : BuildProvider
    {
        IXamlBuildProviderExtension xamlBuildProviderExtension;
        static volatile IXamlBuildProviderExtensionFactory xamlBuildProviderExtensionFactory;
 
        internal new string VirtualPath
        {
            get { return base.VirtualPath; }
        }
 
        public override void GenerateCode(AssemblyBuilder assemblyBuilder)
        {
            XamlType rootXamlType = GetRootXamlType();
 
            this.GetXamlBuildProviderExtension(rootXamlType);
 
            if (this.xamlBuildProviderExtension != null)
            {
                using (Stream xamlStream = base.OpenStream())
                {
                    this.xamlBuildProviderExtension.GenerateCode(assemblyBuilder, xamlStream, this);
                }
            }
        }        
 
        [Fx.Tag.Throws(typeof(TypeLoadException), "The type resolution of the root element failed.")]
        public override Type GetGeneratedType(CompilerResults results)
        {
            if (this.xamlBuildProviderExtension != null)
            {
                Type result = this.xamlBuildProviderExtension.GetGeneratedType(results);
                if (result != null)
                {
                    return result;
                }
            }
            
            try
            {
                XamlType rootXamlType = GetRootXamlType();
                if (rootXamlType.IsUnknown)
                {
                    StringBuilder typeName = new StringBuilder();
                    AppendTypeName(rootXamlType, typeName);
                    throw FxTrace.Exception.AsError(new TypeLoadException(SR.CouldNotResolveType(typeName)));
                }
                return rootXamlType.UnderlyingType;
            }
            catch (XamlParseException ex)
            {
                throw FxTrace.Exception.AsError(new HttpCompileException(ex.Message, ex));
            }
        }        
 
        public override BuildProviderResultFlags GetResultFlags(CompilerResults results)
        {
            return BuildProviderResultFlags.ShutdownAppDomainOnChange;
        }
 
        private void AppendTypeName(XamlType xamlType, StringBuilder sb)
        {
            if (!string.IsNullOrEmpty(xamlType.PreferredXamlNamespace))
            {
                sb.Append("{");
                sb.Append(xamlType.PreferredXamlNamespace);
                sb.Append("}");
            }
            sb.Append(xamlType.Name);
            if (xamlType.IsGeneric)
            {
                sb.Append("(");
                for (int i = 0; i < xamlType.TypeArguments.Count; i++)
                {
                    AppendTypeName(xamlType.TypeArguments[i], sb);
                    if (i < xamlType.TypeArguments.Count - 1)
                    {
                        sb.Append(", ");
                    }
                }
                sb.Append(")");
            }
        }     
 
        XamlType GetRootXamlType()
        {
            try
            {
                using (Stream xamlStream = base.OpenStream())
                {
                    XmlReader xmlReader = XmlReader.Create(xamlStream);
                    XamlXmlReader xamlReader = new XamlXmlReader(xmlReader);
 
                    // Read to the root object
                    while (xamlReader.Read())
                    {
                        if (xamlReader.NodeType == XamlNodeType.StartObject)
                        {
                            return xamlReader.Type;
                        }
                    }
                    throw FxTrace.Exception.AsError(new HttpCompileException(SR.UnexpectedEof));
                }
            }
            catch (XamlParseException ex)
            {
                throw FxTrace.Exception.AsError(new HttpCompileException(ex.Message, ex));
            }
        }
 
        void GetXamlBuildProviderExtension(XamlType rootXamlType)
        {
            if (rootXamlType.UnderlyingType == null)
            {
                return;
            }
 
            this.GetXamlBuildProviderExtensionFactory(rootXamlType);
 
            if (xamlBuildProviderExtensionFactory != null)
            {
                this.xamlBuildProviderExtension = xamlBuildProviderExtensionFactory.GetXamlBuildProviderExtension();
            }
        }
 
        void GetXamlBuildProviderExtensionFactory(XamlType rootXamlType)
        {
            if (xamlBuildProviderExtensionFactory != null)
            {
                return;
            }
 
            // Get the HttpHandler type
            Type httpHandlerType;
            XamlHostingConfiguration.TryGetHttpHandlerType(this.VirtualPath, rootXamlType.UnderlyingType, out httpHandlerType);
            
            if (httpHandlerType != null && typeof(IXamlBuildProviderExtensionFactory).IsAssignableFrom(httpHandlerType))
            {
                xamlBuildProviderExtensionFactory = (IXamlBuildProviderExtensionFactory)Activator.CreateInstance(httpHandlerType,
                    BindingFlags.CreateInstance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance,
                    null, null, null);
            }
        }
    }
}