我們有幾個專案使用了一個共享的公共庫(內部的,不是公共的)。(C#.net專案,使用Visual Studio,設定為解決方案)
解決方案A --||
|----> Common Library (Nuget Package)
解決方案B ---|
這在一般情況下作業正常。通用庫被發布到一個內部的nuget feed中,然后可以被兩個專案所使用,無論是在本地運行還是在構建服務器上。
問題是當我們想要對通用庫進行更改時。似乎測驗這些更改的唯一方法是重建公共庫,將更新后的包發布到饋送中,升級專案 A 中的包(由于解決方案中存在大量專案,因此需要一段時間),然后進行測驗。這個周期需要很長的時間。
在理想情況下,我所尋找的是一種方法,即能夠在專案 A(或 B)的同一解決方案中包含通用庫專案,并對庫進行修改,然后作為一個解決方案運行和除錯代碼。但這樣做要花很多時間。它需要查看專案A中所有的csproj檔案,并將所有的參考改為專案參考而不是包參考。我試著在csproj檔案中使用條件,以便在使用本地專案和使用nuget包進行構建之間輕松切換,但這似乎并不有效。Visual studio似乎對這些參考感到困惑,并且構建失敗。
有什么替代方案嗎?我覺得這應該是一個相當普遍的情況,所以是否有一個公認的典型設定方法,以便既能使用nuget包來構建通用庫,又能將它們連接在一起并輕松進行除錯。
作為對 @vernou 的回應,這是我們試圖在 csproj 檔案中用條件屬性來設定的東西。我們設定了一個配置型別來控制使用哪個參考。
<ItemGroup Condition=" '$(配置)' == 'DebugWithLocalCommon'" >
<ProjectReference Include="$(CommonPath)Common.Project.NameCommon.Project.Name.csproj"/span>>。
<專案>{111111-1111-1111}</Project>
<Name>Common.Project.Name</Name>
</ProjectReference>
...
多個專案參考繼續這里
...
</ItemGroup>
<ItemGroup Condition=" '$(Configuration)' != 'DebugWithLocalCommon'" >
<Reference Include="Common.Project.Name, Version=4.0.26.0, Culture=neutral, PublicKeyToken=11111111111111, processorArchitecture=MSIL">
<HintPath>.packagesCommon.Project.Name.4.0.26lib
etstandard2.0Common.Project.Name.dll</HintPath>
</Reference>
...
多個包的參考繼續這里
...
</ItemGroup>
實際上,我們有一些專案使用經典的csproj參考格式(如上),還有一些專案使用較新的 "包參考 "格式來參考nuget包。在這些情況下,第二塊會更像這樣:
<ItemGroup Condition=" '$(Configuration)' != 'DebugWithLocalCommon'" /span>>
<PackageReference Include="Common.Project.Name"/span>>
<版本>4.0.26</Version>
</PackageReference>
...
多個軟體包參考 繼續這里
...
</ItemGroup>
我們在這方面遇到的問題是,它似乎使visual studio感到困惑。有時,多個參考應該出現在用戶界面中(這也許只是令人討厭,而不是一個完全的破壞者),但有時它也似乎完全不能理解參考,并拒絕構建或識別正在參考的包,只是給出 "你可能缺少一個參考 "型別的錯誤。
我們也嘗試過在 csproj 中使用同樣的方法,但結果是完全一樣的。
。uj5u.com熱心網友回復:
這是一個挑戰,解決方案相當復雜。它也取決于你的原始碼控制和開發環境是如何設定的。但是有一個潛在的解決方案,我可以解釋一下。
簡而言之,您需要一個自定義工具,它可以只是一個命令列exe專案,它將更新csproj檔案中的參考,而不需要進行所有的手動更改。
開發環境的設定:
你會發現,作為個人,開發人員可能都會將源代碼克隆到他們機器上的不同位置。因此,每個人都將他們的代碼放在不同的地方。只要每個人在主檔案夾中擁有相同的結構就可以了,這樣就可以使用相對位置來添加參考。
EG,如果每個人都使用。
C:SourceCommon
C:SourceApp1
或者。
C:CodeCommon
C:CodeApp1
這很好,但是如果公共檔案夾在某些人的機器上被稱為 "cmn",這對他們來說將是一個問題。
所以現在,在 VS 中你可以在 App1 中使用相對位置對你的 Common 專案進行專案參考,例如。 ...Common.csproj
專案型別問題:
你需要考慮你有什么型別的專案。例如,如果你在Visual Studio中創建一個新的專案并使用.Net Framework 4.xx,你將擁有現在所謂的 "舊 "專案型別。如果你用.Net Standard或.Net Core創建,你將得到新的專案型別(特別是在做所有這些nuget的事情時,它更漂亮)。
舊專案型別在每個專案的 packages.config 中參考了所有 nuget 包。它也有一個對實際專案的參考,包括csproj中的確切路徑和版本。這就是使程序更加繁瑣的原因。
新的專案型別在csproj檔案中只有對nuget包的參考(超級超級)。
但是,如果你仍然擁有舊的專案型別,這并不重要,自定義工具仍然有可能處理這個問題。
該工具:
這只是基礎知識,所以不是一個完整的解決方案,但希望你能從中獲得足夠的資訊來實施。
確保你在一個副本上進行測驗,或者先啟動一個新的分支,以確保沒有任何永久性的損壞。這將只滿足舊式專案的需要,我想你正在使用這個專案。
創建一個新的控制臺應用程式專案,并添加一些處理檔案的基本類:
PackageConfig.cs[Serializable]
[DesignerCategory("code")]
[XmlType(AnonymousType = true, IncludeInSchema = true)]
[XmlRoot(ElementName = "packages", IsNullable = false)]。
public class PackageConfig
{
[XmlElement("package")]
public Package[] Packages { get; set; }
}
[Serializable] 。
[DesignerCategory("code")]
public class Package
{
[XmlAttribute("id")]
public string Id { get; set; }
[XmlAttribute("version"/span>)]
public string Version { get; set; }
[XmlAttribute("targetFramework")]
public string TargetFramework { get; set; }
XmlSerializer.cx
class XmlSerializer
{
private System.Xml.Serialization.XmlSerializer GetSerializer<T> ()
{
return new System.Xml.Serialization.XmlSerializer(typeof(T)) 。
}
public string Serialize< T>(T instance, bool omitXmlDeclaration = false)
{
System.Xml.Serialization.XmlSerializer xmlSerializer = GetSerializer<T>()。
StringBuilder stringBuilder = new StringBuilder()。
XmlWriterSettings = new XmlWriterSettings
{
OmitXmlDeclaration = omitXmlDeclaration,
編碼 = Encoding.UTF8
};
using (XmlWriter writer = XmlWriter.Create(new StringWriter(stringBuilder), settings)
{
xmlSerializer.Serialize(writer, instance)。
}
return stringBuilder.ToString()。
}
public T Deserialize< T>(string xml)。
{
System.Xml.Serialization.XmlSerializer xmlSerializer = GetSerializer<T>()。
using (XmlTextReader reader = new XmlTextReader(new StringReader(xml))
return (T)xmlSerializer.Deserialize(reader)。
}
更新你的program.cs為:
class Program
{
static void Main(string[] args)?
{
try
{
string packageVersion = null;
if (args != null && args.length == 1)
packageVersion = args[0] 。
UpdateProjects(packageVersion)。
}
catch (Exception ex)
{
Console.Error.WriteLine(ex.ToString())。
}
}
const string _packageId = "Common";
delegate string UpdateContent(string content) 。
static void UpdateProjects(string packageVersion)。
{
if (packageVersion == null)
UseLocalReferences()。
else (packageVersion == null)
UsePackageReferences(packageVersion)。
}
static void UseLocalReferences()
{
RemoveNugetPackage()。
ProcessProjects(content =>
{
content = RemoveReference(content);
content = AddReference(content, null)。
return content。
});
}
static void UsePackageReferences(string packageVersion)。
{
AddNugetPackage(packageVersion)。
ProcessProjects(content =>
{
content = RemoveReference(content);
content = AddReference(content, packageVersion);
return content。
});
}
static void ProcessProjects(UpdateContent update)
{
string folder = Environment.CurrentDirectory;
string[] files = Directory.GetFiles(folder, "*.csproj"/span>, SearchOption.AllDirectories)。
foreach (string fileName in files)
{
try try
{
string content = File.ReadAllText(fileName);
content = update(content);
using (StreamWriter writer = new StreamWriter(fileName)
{
writer.Write(content)。
}
Console.WriteLine("更新:" fileName)。
}
catch (Exception ex)
{
Console.Error.WriteLine($"錯誤更新 {fileName}:")。
Console.Error.WriteLine(ex.ToString())。
}
}
}
static void RemoveNugetPackage()。
{
string folder = Environment.CurrentDirectory;
Console.WriteLine($"更新{folder}下的所有軟體包.組態檔")。
XmlSerializer xmlSerializer = new XmlSerializer()。
string[] packageConfigFiles = Directory.GetFiles(folder, "packages.config", SearchOption.AllDirectories) 。
foreach (string packageConfigFile in packageConfigFiles)
{
PackageConfig packageConfig = xmlSerializer.Deserialize<PackageConfig>(File.ReadAllText(packageConfigFile))。
List<Package> packages = new List<Package>(packageConfig.Packages)。
if (packages.Any(x => x.Id == _packageId))
packages.First(x => x.Id == _packageId).Version = packageVersion。
else[/span
packages.Add(new Package { Id = _packageId, Version = packageVersion, TargetFramework = "net462" }); //可能需要改變這里的框架。
packages.Sort((x, y) => string.Compare(x.Id, y.Id))。
packageConfig.Packages = packages.ToArray();
File.WriteAllText(packageConfigFile, xmlSerializer.Serialize(packageConfig))。
Console.WriteLine($"{packageConfigFile} updated")。
}
Console.WriteLine("package.config files的更新完成")。
}
static void AddNugetPacket。 title">AddNugetPackage(string packageVersion)。
{
string folder = Environment.CurrentDirectory;
Console.WriteLine($"更新{folder}下的所有包.組態檔")。
XmlSerializer xmlSerializer = new XmlSerializer()。
string[] packageConfigFiles = Directory.GetFiles(folder, "packages.config", SearchOption.AllDirectories) 。
foreach (string packageConfigFile in packageConfigFiles)
{
PackageConfig packageConfig = xmlSerializer.Deserialize<PackageConfig>(File.ReadAllText(packageConfigFile))。
List<Package> packages = new List<Package>(packageConfig.Packages)。
Package package = packages.FirstOrDefault(x => x.Id == _packageId)。
if (package != null)
packages.Remove(package)。
packageConfig.Packages = packages.ToArray();
File.WriteAllText(packageConfigFile, xmlSerializer.Serialize(packageConfig))。
Console.WriteLine($"{packageConfigFile} updated")。
}
Console.WriteLine("package.config files的更新完成")。
}
static string RemoveReference(span class="hljs-built_in">string content)
{
string[] lines = content.Split(new string[] {"
" },StringSplitOptions.None)。)
StringBuilder sb = new StringBuilder()。
bool removing = false;
foreach (string line in lines)
{
if (!driving && line.Trim().StartsWith($"<Reference Include="{_packageId}"))
removing = true;
else if (removing)
{
if (line.Trim() == "</Reference>"/span>)
removing = false;
}
else
sb.AppendLine(line)。
}
return sb.ToString()。
}
static string AddReference(string content。stringpackageVersion)。
{
string[] lines = content.Split(new string[] { "
" },StringSplitOptions.None)。)
StringBuilder sb = new StringBuilder()。
foreach (string line in lines)
{
if (line.Trim() == "<Reference Include="System" />"/span>) //找到需要插入參考的地方。
{
if (packageVersion == null)
{
sb.AppendLine($" <Reference Include="{_packageId}" >")。
sb.AppendLine($" <SpecificVersion>False</SpecificVersion>") 。
sb.AppendLine($" <HintPath>.Commonin$(Configuration){_packageId}.dll</HintPath> ")。
sb.AppendLine($" </Reference>") 。
}
else
{
sb.AppendLine($" <Reference Include="{_packageId}, Version = {packageVersion}, Culture = neutral, processorArchitecture = MSIL" >")。
sb.AppendLine($" <HintPath>.packages{_packageId}. {packageVersion}libnet462{_packageId}.dll</HintPath>"); //再次,框架可能需要更新。
sb.AppendLine($" </Reference>")。
}
}
sb.AppendLine(line)。
}
return sb.ToString()。
}
}
使用該工具:
當你編譯該工具時,將exe復制到你的主專案檔案夾,EG C:SourceApp1 - 然后你可以用以下方法運行它:
updatetool
(以設定本地參考)
或者
updatetool 1.0.1。
(以設定到nuget包和參考)
這都是未經測驗的,但基于我使用的相同的解決方案!
uj5u.com熱心網友回復:如果你使用git,也許可以使用git-submodule。
我有一個類似的情況。我為 Entity Framework Core 開發了一個自定義提供商,為了幫助開發,我使用 EF Core 代碼源進行除錯。
csproj看起來像 :
<Project Sdk="Microsoft.NET.Sdk"/span>>
...
<ItemGroup Condition=" '$(配置)'!
<PackageReference Include="Microsoft. EntityFrameworkCore.Relational" Version="[3.1,4)" />
</ItemGroup>
<ItemGroup Condition=" '$(配置)'=='Debug'">
<ProjectReference Include=" .efcoresrcEFCore. RelationalEFCore.Relational.csproj" PrivateAssets="contentfiles;build" />
</ItemGroup>
</Project>/span>
當我在Debug中啟動我的專案時,我也可以除錯EF Core的代碼源,但當我在Release中啟動時,NuGet包被使用,我無法訪問EF Core的代碼源。
使用git的好處 :
我們使用 git 來對我們的代碼源進行版本管理。如果我的同事得到了代碼源并試圖進行除錯,這將失敗,因為EF Core不存在。
然后我把EF Core作為子模塊添加到我們的git倉庫中:
我把EF Core作為子模塊添加到我們的git倉庫中。
git submodule add https:/github.com/dotnet/efcore.git
#加載一個特定的版本。
cd efcore
git checkout v3.1.18
cd .../
git commit -m "添加子模塊efcore"。
現在,當我的同事克隆我們的供應商倉庫時,EF Core的代碼源會自動加載(只需要在從Visual Studio克隆時檢查'加載子模塊'的情況)。
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/316546.html
標籤:
