Long code warning...
The following console app seems to work for key-containers (I try to avoid
working with key-files); using this and the information in my reply
yesterday, plus "before vs after" (windiff) at what exactly the UI does to
the project file when setting the key-file in the IDE, you should be able to
get it to work with key-files in about half-an-hour. I haven't tested it
much... you may need to fix bits of it... but it worked for my test cases.
Good luck.
Marc
===
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Diagnostics;
using System.Xml;
using System.Text.RegularExpressions;
namespace AssemblyKey {
class Program {
static bool _verbose = false;
static int Main(string[] args) {
List<string> projects = new List<string>();
bool recurse = false, valid = true, showHelp = false;
foreach (string arg in args) {
if (arg.StartsWith("-")) {
switch(arg) {
case "-h":
case "-?":
showHelp = true; break;
case "-r":
recurse = true; break;
case "-v":
_verbose = true; break;
default:
Console.WriteLine("Invalid option \"{0}\"",
arg);
valid = false; break;
}
} else {
string path = arg;
if (PreCheckProject(ref path)) {
projects.Add(path);
} else {
valid = false;
}
}
if(recurse) {
try { // following can fail for various recursive
reasons
foreach (string pathItem in
Directory.GetFiles(Environment.CurrentDirectory, "*.csproj",
SearchOption.AllDirectories)) {
string path = pathItem; // ref/foreach
if (PreCheckProject(ref path)) {
projects.Add(path);
} else {
valid = false;
}
}
} catch (Exception ex) {
Console.WriteLine(ex.GetType().Name + ": " +
ex.Message);
valid = false; // but keep going anyway
}
}
}
if (projects.Count == 0)
showHelp = true;
if (valid) {
if (showHelp) {
Console.WriteLine("\t{0} -? | -h | -r | {{project path
[project path...]} [-v]}", Process.GetCurrentProcess().ProcessName);
Console.WriteLine("\t\t-r\t\tRecurse from current
directory");
Console.WriteLine("\t\t-v\t\tVerbose");
Console.WriteLine("\t\t-?, -h\t\tHelp");
} else {
foreach (string path in projects) {
try {
ProcessProject(path);
} catch (Exception ex) {
Console.WriteLine(ex.GetType().Name + ": " +
ex.Message);
valid = false; // but keep going anyway
}
}
}
}
return valid ? 0 : -1;
}
static bool IsFileReadOnly(string path) {
return (File.GetAttributes(path) & FileAttributes.ReadOnly) ==
FileAttributes.ReadOnly;
}
static bool PreCheckProject(ref string path) {
path = Path.GetFullPath(path);
if (!File.Exists(path)) {
Console.WriteLine("File not found: {0}", path);
return false;
}
if (IsFileReadOnly(path)) {
Console.WriteLine("File is read only: {0}", path);
return false;
}
return true;
}
static void ProcessProject(string path) {
Verbose("Processing {0}", path);
bool update = false;
string projectRoot = new FileInfo(path).Directory.FullName;
XmlDocument project = new XmlDocument();
project.Load(path);
XmlNamespaceManager nm = new
XmlNamespaceManager(project.NameTable);
nm.AddNamespace("x", project.DocumentElement.NamespaceURI);
XmlElement group =
(XmlElement)project.SelectSingleNode("/x:Project/x:PropertyGroup[not(@Condition)][1]",
nm);
foreach(XmlElement el in
project.SelectNodes("/x:Project/x:ItemGroup/x:Compile[@Include]", nm)) {
string classFile = el.SelectSingleNode("@Include").Value;
if (classFile.EndsWith("AssemblyInfo.cs")) {
string keyName;
ProcessAssemblyInfo(Path.Combine(projectRoot,
classFile), out keyName);
if (!string.IsNullOrEmpty(keyName)) {
update |= SetChildElement(group, "KeyContainerName",
keyName);
}
}
}
if (update) {
project.Save(path);
}
}
private static bool SetChildElement(XmlElement parent, string
elementName, string value) {
bool updated = false;
XmlDocument doc = parent.OwnerDocument;
XmlNamespaceManager nm = new XmlNamespaceManager(doc.NameTable);
nm.AddNamespace("x", parent.NamespaceURI);
XmlElement child = (XmlElement)parent.SelectSingleNode("x:" +
elementName, nm);
if (child == null) {
child =
(XmlElement)parent.AppendChild(doc.CreateElement(e lementName,parent.NamespaceURI));
child.InnerText = value;
Verbose("Added element {0} = {1}", elementName, value);
updated = true;
} else if(child.InnerText != value) {
child.InnerText = value;
Verbose("Updated element {0} = {1}", elementName, value);
updated = true;
}
return updated;
}
private static void Verbose(string format, params object[] args) {
if (_verbose) {
Console.WriteLine(format, args);
}
}
static Regex _keyFileRegex = new
Regex(@"(\[\s*assembly:\s*AssemblyKeyName\(\s*"")([^""]*)(""\s*\)\s*\])",
RegexOptions.Compiled);
static void ProcessAssemblyInfo(string path, out string keyName) {
Verbose("Processing {0}", path);
keyName = null;
bool update = false;
string allText = File.ReadAllText(path);
Match match = _keyFileRegex.Match(allText);
if (match.Success) {
keyName = match.Groups[2].Value;
Verbose("Found key-name {0}", keyName);
allText = _keyFileRegex.Replace(allText, "");
update = true;
}
if (update) {
File.WriteAllText(path, allText);
}
}
}
}