📄 manifestsettings.cs
字号:
//============================================================================================================
// Microsoft Updater Application Block for .NET
// http://msdn.microsoft.com/library/en-us/dnbda/html/updater.asp
//
// ManifestSettings.cs
//
//============================================================================================================
// Copyright (C) 2000-2001 Microsoft Corporation
// All rights reserved.
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR
// FITNESS FOR A PARTICULAR PURPOSE.
//============================================================================================================
using System;
using System.Collections;
using System.Xml;
using System.IO;
using System.Reflection;
using System.Runtime.Remoting;
using Microsoft.ApplicationBlocks.ApplicationUpdater.Interfaces;
namespace ManifestUtility
{
/// <summary>
/// Summary description for ManifestSettings.
/// </summary>
public class ManifestSettings
{
#region delarations
private string _folderPath = "";
private string _updateLocation = "";
private string _version = "";
private string _key = "";
private bool _usePostProcessor = false;
private string _postProcessorAssembly = "";
private string _postProcessorClass = "";
private string _validatorAssembly = "";
private string _validatorClass = "";
private ArrayList filesForUpdate;
private IValidator validator;
#endregion
#region constructor
public ManifestSettings()
{
}
#endregion
#region properties
public string FolderPath
{
get
{
return _folderPath;
}
set
{
_folderPath = value;
}
}
public string UpdateLocation
{
get
{
return _updateLocation;
}
set
{
_updateLocation = value;
}
}
public string Version
{
get
{
return _version;
}
set
{
_version = value;
}
}
public string Key
{
get
{
return _key;
}
set
{
_key = value;
}
}
public bool UsePostProcessor
{
get
{
return _usePostProcessor;
}
set
{
_usePostProcessor = value;
}
}
public string PostProcessorAssembly
{
get
{
return _postProcessorAssembly;
}
set
{
_postProcessorAssembly = value;
}
}
public string PostProcessorClass
{
get
{
return _postProcessorClass;
}
set
{
_postProcessorClass = value;
}
}
public string ValidatorAssembly
{
get
{
return _validatorAssembly;
}
set
{
_validatorAssembly = value;
}
}
public string ValidatorClass
{
get
{
return _validatorClass;
}
set
{
_validatorClass = value;
}
}
#endregion
public XmlDocument Create()
{
XmlDocument xmlDoc = new XmlDocument();
XmlNode node = null;
XmlNode filesNode = null;
XmlNode fileNode = null;
XmlAttribute attribute = null;
string signature = "";
// Instantiate the validator
ObjectHandle handle = Activator.CreateInstanceFrom( this.ValidatorAssembly, this.ValidatorClass );
object instance = handle.Unwrap();
validator = ( IValidator )instance;
// get all files first
PutFilesInCollection();
// now actually generate xml
try
{
// tell xml to keep white space
xmlDoc.PreserveWhitespace = true;
#region Create Main ServerManifest Xml Nodes
xmlDoc.AppendChild( xmlDoc.CreateElement( "ServerApplicationInfo" ) );
// create/set available version
node = xmlDoc.SelectSingleNode( "ServerApplicationInfo" ).AppendChild( xmlDoc.CreateElement( "availableVersion" ) );
node.InnerText = this.Version;
// create/set update URL root
node = xmlDoc.SelectSingleNode( "ServerApplicationInfo" ).AppendChild( xmlDoc.CreateElement( "updateLocation" ) );
node.InnerText = this.UpdateLocation;
// create the files node, which will have individual file nodes added later
xmlDoc.SelectSingleNode( "ServerApplicationInfo" ).AppendChild( xmlDoc.CreateElement( "files" ) );
#endregion
// select the "files" node for quick appending in following loop:
filesNode = xmlDoc.SelectSingleNode( "ServerApplicationInfo/files" );
foreach ( FileInfo fInfo in filesForUpdate )
{
#region Append File Node; Add Attributes and their Values
// append a new file node to "files" node, get reference to that new file node
fileNode = filesNode.AppendChild( xmlDoc.CreateElement( "file" ) );
// using new file node, append attributes
attribute = fileNode.Attributes.Append( xmlDoc.CreateAttribute( "name" ) );
// Updater will require relative paths to root to reconstruct dir structure at destination
// manipulate our known Root dir and current filename to derive relative path;
// use Utility to remove initial slash, because
// OUR CONVENTION IS ALL ROOT PATHS TERMINATE WITH SLASH, ALL RELATIVE PATHS DO NOT INITIATE WITH SLASH
string relPath = ExtractRelativePath( fInfo.FullName, this.FolderPath );
// make the slashes go the right way
int lastFwdSlash = this.UpdateLocation.LastIndexOf("/");
int lastBckSlash = this.UpdateLocation.LastIndexOf(@"\@");
if ( lastFwdSlash > lastBckSlash)
{
relPath = relPath.Replace(@"\", "/");
}
attribute.Value = relPath;
// using new file node, append attributes
attribute = fileNode.Attributes.Append( xmlDoc.CreateAttribute( "signature" ) );
// use Validation utility to get signature:
// CHECK, if validator null then signing not desired
if( null != validator )
{
signature = validator.Sign( fInfo.FullName, this.Key );
}
else
{
signature = "";
}
// set signature attribute value
attribute.Value = signature;
#endregion
} // FOREACH
#region Add Post-Processing Assembly Information
// skip post-processor if told to omit, or if no object instance available
if( ( this.UsePostProcessor ) && ( null != this.PostProcessorClass ) )
{
CreatePostProcessingAttribute( xmlDoc );
}
#endregion
#region **** SIGN MANIFEST **** : Add Keyed Hash "Signature" to Root Element
SignManifest( xmlDoc );
return xmlDoc;
#endregion
}
catch( Exception e )
{
throw e;
}
}
private void CreatePostProcessingAttribute( XmlDocument xmlDoc )
{
XmlAttribute attribute = null;
XmlNode node = null;
// create the node for IPP
// check if it exists first
node = xmlDoc.SelectSingleNode( "ServerApplicationInfo/postProcessor" );
if( null == node )
{
node = xmlDoc.SelectSingleNode( "ServerApplicationInfo" ).AppendChild( xmlDoc.CreateElement( "postProcessor" ) );
}
// find and load post-processing assembly
// ALWAYS it implements IPostProcessor which presents known "void Run()" to AppUpdater
//DESIGN: we always choose the FIRST instance of IPostProcessor we found...
try
{
// the type attr
attribute = node.Attributes.Append( xmlDoc.CreateAttribute( "type" ) );
attribute.Value = this.PostProcessorClass;
// the assembly attr
attribute = node.Attributes.Append( xmlDoc.CreateAttribute( "assembly" ) );
Assembly asm = Assembly.LoadFrom(this.PostProcessorAssembly);
attribute.Value = asm.FullName;
// the filename attr
attribute = node.Attributes.Append( xmlDoc.CreateAttribute( "name" ) );
// use Utility function to get the UN-pre-slashed relative path to this assembly
attribute.Value = ExtractRelativePath( this.PostProcessorAssembly, this.FolderPath );
}
catch (Exception ex)
{
throw ex;
}
}
private void SignManifest( XmlDocument xmlDoc )
{
string signature = "";
XmlAttribute attribute = null;
#region Add Keyed Hash "Signature" to Root Element
// check if signature attribute exists already
attribute = (XmlAttribute)xmlDoc.SelectSingleNode( "ServerApplicationInfo/@signature" );
if( null == attribute )
{
// create the MANIFEST's signature attribute--we pass the contents of the ServerApplicationInfo node
// to validator to generate a keyed hash of everything inside this root node; client then validates
// server manifest
attribute = xmlDoc.SelectSingleNode( "ServerApplicationInfo" ).Attributes.Append( xmlDoc.CreateAttribute( "signature" ) );
}
// pass contents of root node to validator for "signing" with keyed hash;
// IF validator is null, don't sign
if( null != validator )
{
signature = validator.Sign
(
xmlDoc.SelectSingleNode( "ServerApplicationInfo" ),
this.Key
);
}
// put hash signature value in signature attribute obtained above
attribute.Value = signature ;
#endregion
}
private void PutFilesInCollection()
{
// check to be sure _folderpath is valid first
if ( Directory.Exists( this.FolderPath ) )
{
// set files member to new arraylist
filesForUpdate = new ArrayList();
// using member _folderpath, populate member MakerState.filesForUpdate with all files in target directory
filesForUpdate = GetAllFiles( this.FolderPath );
}
}
/// <summary>
/// Recursive function that walks given folder path and adds all files to the MakerState.filesForUpdate collection
/// </summary>
/// <param name="folderPath">the root directory to start with; function is recursive so will walk subdirs too</param>
private ArrayList GetAllFiles( string folderPath )
{
DirectoryInfo dirInfo = new DirectoryInfo( folderPath );
foreach( FileSystemInfo fsi in dirInfo.GetFileSystemInfos() )
{
if ( fsi is FileInfo )
{
filesForUpdate.Add( fsi );
}
else
{
// it's not a file must be a folder; recurse rinse repeat fold manipulate
GetAllFiles( fsi.FullName );
}
}
return filesForUpdate;
}
private string ExtractRelativePath( string fullPath, string rootPath )
{
string relativeFilePath = "";
relativeFilePath = fullPath.Substring( rootPath.Length, ( fullPath.Length - rootPath.Length ) );
relativeFilePath = RemoveInitialSlash( relativeFilePath );
return relativeFilePath;
}
private string RemoveInitialSlash( string path )
{
string outPath = path;
if( path.IndexOf( @"\" ) == 0 )
{
outPath = path.Substring( 1, ( path.Length - 1 ) );
}
if( path.IndexOf( "/" ) == 0 )
{
outPath = path.Substring( 1, ( path.Length - 1 ) );
}
return outPath;
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -