|
#region Copyright (c) Microsoft Corporation
/// <copyright company='Microsoft Corporation'>
/// Copyright (c) Microsoft Corporation. All Rights Reserved.
/// Information Contained Herein is Proprietary and Confidential.
/// </copyright>
#endregion
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
#if WEB_EXTENSIONS_CODE
using System.Web.Resources;
#else
using Microsoft.VSDesigner.WCF.Resources;
#endif
#if WEB_EXTENSIONS_CODE
namespace System.Web.Compilation.WCFModel
#else
namespace Microsoft.VSDesigner.WCFModel
#endif
{
/// <summary>
/// Map file loader
/// </summary>
/// <remarks>
/// MapFileLoader instance and MapFile instance should be 1:1 mapping.
/// </remarks>
#if WEB_EXTENSIONS_CODE
internal abstract class MapFileLoader
#else
[CLSCompliant(true)]
public abstract class MapFileLoader
#endif
{
/// <summary>
/// Save the given map file.
/// </summary>
/// <param name="mapFile">The map file to be saved</param>
public void SaveMapFile(MapFile mapFile)
{
Debug.Assert(mapFile != null, "mapFile is null!");
SaveExternalFiles(mapFile);
using (var mapFileWriter = GetMapFileWriter())
{
GetMapFileSerializer().Serialize(mapFileWriter, Unwrap(mapFile));
}
}
/// <summary>
/// Load the map file.
/// </summary>
/// <returns>Concrete map file instance.</returns>
public MapFile LoadMapFile()
{
MapFile mapFile = null;
using (var mapFileReader = GetMapFileReader())
{
var proxyGenerationErrors = new List<ProxyGenerationError>();
ValidationEventHandler handler =
(sender, e) =>
{
bool isError = (e.Severity == XmlSeverityType.Error);
proxyGenerationErrors.Add(
new ProxyGenerationError(ProxyGenerationError.GeneratorState.LoadMetadata,
MapFileName,
e.Exception,
!isError));
if (isError)
{
throw e.Exception;
}
};
var readerSettings = new XmlReaderSettings()
{
Schemas = GetMapFileSchemaSet(),
ValidationType = ValidationType.Schema,
ValidationFlags = XmlSchemaValidationFlags.ReportValidationWarnings,
};
using (XmlReader reader = XmlReader.Create(mapFileReader, readerSettings, string.Empty))
{
try
{
readerSettings.ValidationEventHandler += handler;
mapFile = ReadMapFile(reader);
SetMapFileLoadErrors(mapFile, proxyGenerationErrors);
}
finally
{
readerSettings.ValidationEventHandler -= handler;
}
}
}
if (mapFile != null)
{
LoadExternalFiles(mapFile);
}
return mapFile;
}
/// <summary>
/// Load metadata file from file system
/// </summary>
public void LoadMetadataFile(MetadataFile metadataFile)
{
try
{
metadataFile.CleanUpContent();
metadataFile.LoadContent(ReadMetadataFile(metadataFile.FileName));
}
catch (Exception ex)
{
metadataFile.ErrorInLoading = ex;
}
}
/// <summary>
/// Load extension file
/// </summary>
public void LoadExtensionFile(ExtensionFile extensionFile)
{
try
{
extensionFile.CleanUpContent();
extensionFile.ContentBuffer = ReadExtensionFile(extensionFile.FileName);
}
catch (Exception ex)
{
extensionFile.ErrorInLoading = ex;
}
}
#region protected abstract methods
/// <summary>
/// The name of the file where the MapFile instance is loaded.
/// </summary>
protected abstract string MapFileName { get; }
/// <summary>
/// Wrap the map file impl.
/// </summary>
protected abstract MapFile Wrap(object mapFileImpl);
/// <summary>
/// Unwrap the map file.
/// </summary>
protected abstract object Unwrap(MapFile mapFile);
/// <summary>
/// Get the map file schema set
/// </summary>
/// <return>Xml schema set of the map file</return>
protected abstract XmlSchemaSet GetMapFileSchemaSet();
/// <summary>
/// Get the map file serializer
/// </summary>
/// <returns>Xml serializer of the map file</returns>
protected abstract XmlSerializer GetMapFileSerializer();
/// <summary>
/// Get access to a text reader that gets access to the map file byte stream
/// </summary>
/// <returns>Text reader of the map file</returns>
protected virtual TextReader GetMapFileReader()
{
throw new NotImplementedException();
}
/// <summary>
/// Get access to a text writer that writes the map file byte stream.
/// </summary>
/// <returns>Text writer of the map file</returns>
protected virtual TextWriter GetMapFileWriter()
{
throw new NotImplementedException();
}
/// <summary>
/// Get access to a byte array that contain the contents of the given metadata
/// file
/// </summary>
/// <param name="name">
/// Name of the metadata file. Could be a path relative to the svcmap file location
/// or the name of an item in a metadata storage.
/// </param>
/// <returns>Content of the metadata file</returns>
protected virtual byte[] ReadMetadataFile(string name)
{
throw new NotImplementedException();
}
/// <summary>
/// Write the metadata file.
/// </summary>
/// <param name="file">The metadata file to be written</param>
protected virtual void WriteMetadataFile(MetadataFile file)
{
throw new NotImplementedException();
}
/// <summary>
/// Get access to a byte array that contain the contents of the given extension
/// file
/// </summary>
/// <param name="name">
/// Name of the extension file. Could be a path relative to the svcmap file location
/// or the name of an item in a metadata storage.
/// </param>
/// <returns>Content of the extension file</returns>
protected virtual byte[] ReadExtensionFile(string name)
{
throw new NotImplementedException();
}
/// <summary>
/// Write the extension file.
/// </summary>
/// <param name="file">The extension file to be written</param>
protected virtual void WriteExtensionFile(ExtensionFile file)
{
throw new NotImplementedException();
}
#endregion protected abstract methods
#region private methods
private MapFile ReadMapFile(XmlReader reader)
{
try
{
return Wrap(GetMapFileSerializer().Deserialize(reader));
}
catch (InvalidOperationException ex)
{
XmlException xmlException = ex.InnerException as XmlException;
if (xmlException != null)
{
// the innerException contains detail error message
throw xmlException;
}
XmlSchemaException schemaException = ex.InnerException as XmlSchemaException;
if (schemaException != null)
{
if (schemaException.LineNumber > 0)
{
// append line/position to the message
throw new XmlSchemaException(String.Format(CultureInfo.CurrentCulture,
WCFModelStrings.ReferenceGroup_AppendLinePosition,
schemaException.Message,
schemaException.LineNumber,
schemaException.LinePosition),
schemaException,
schemaException.LineNumber,
schemaException.LinePosition);
}
else
{
throw schemaException;
}
}
// It's something we can't handle, throw it.
throw;
}
}
private void SaveExternalFiles(MapFile mapFile)
{
// KEEP the order! The name of metadata files could be adjusted when we save them.
foreach (MetadataFile metadataFile in mapFile.MetadataList)
{
if (metadataFile.ErrorInLoading == null)
{
WriteMetadataFile(metadataFile);
}
}
foreach (ExtensionFile extensionFile in mapFile.Extensions)
{
if (extensionFile.ErrorInLoading == null)
{
WriteExtensionFile(extensionFile);
}
}
}
private void LoadExternalFiles(MapFile mapFile)
{
// Do basic check for metadata files and extension files.
ValidateMapFile(mapFile);
foreach (MetadataFile metadataFile in mapFile.MetadataList)
{
metadataFile.IsExistingFile = true;
LoadMetadataFile(metadataFile);
}
foreach (ExtensionFile extensionFile in mapFile.Extensions)
{
extensionFile.IsExistingFile = true;
LoadExtensionFile(extensionFile);
}
}
private void ValidateMapFile(MapFile mapFile)
{
var metadataFileNames = mapFile.MetadataList.Select(p => p.FileName).Where(p => !string.IsNullOrEmpty(p));
var extensionFileNames = mapFile.Extensions.Select(p => p.FileName).Where(p => !string.IsNullOrEmpty(p));
var fileNameSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
foreach (string fileName in metadataFileNames.Concat(extensionFileNames))
{
if (!fileNameSet.Contains(fileName))
{
fileNameSet.Add(fileName);
}
else
{
throw new FormatException(String.Format(CultureInfo.CurrentCulture,
WCFModelStrings.ReferenceGroup_TwoExternalFilesWithSameName,
fileName));
}
}
}
private void SetMapFileLoadErrors(MapFile mapFile, IEnumerable<ProxyGenerationError> proxyGenerationErrors)
{
mapFile.LoadErrors = proxyGenerationErrors;
}
#endregion private methods
}
}
|