mirror of
https://github.com/2dust/v2rayN.git
synced 2025-08-29 22:36:20 +00:00
Add Singbox Geo RuleSet setting
This commit is contained in:
parent
e0cea929ea
commit
24e7258534
16 changed files with 756 additions and 472 deletions
|
@ -43,6 +43,7 @@ namespace v2rayN
|
|||
public const string TunSingboxRulesFileName = "v2rayN.Sample.tun_singbox_rules";
|
||||
public const string DNSV2rayNormalFileName = "v2rayN.Sample.dns_v2ray_normal";
|
||||
public const string DNSSingboxNormalFileName = "v2rayN.Sample.dns_singbox_normal";
|
||||
public const string SingboxGeoRuleSetsFileName = "v2rayN.Sample.singbox_geo_rulesets";
|
||||
|
||||
public const string DefaultSecurity = "auto";
|
||||
public const string DefaultNetwork = "tcp";
|
||||
|
|
|
@ -1780,5 +1780,44 @@ namespace v2rayN.Handler
|
|||
}
|
||||
|
||||
#endregion DNS
|
||||
|
||||
#region Sing Geo RuleSets
|
||||
|
||||
public static int InitBuiltinSingGeoRuleSets(Config config)
|
||||
{
|
||||
var item = LazyConfig.Instance.GetSingGeoRuleSets();
|
||||
if (item is not null && item.rules != "")
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
var item2 = new SingGeoRuleSet()
|
||||
{
|
||||
id = Utils.GetGUID(false),
|
||||
remarks = "sing-box",
|
||||
rules = Utils.GetEmbedText(Global.SingboxGeoRuleSetsFileName),
|
||||
};
|
||||
return SaveSingGeoRuleSet(config, item2);
|
||||
}
|
||||
|
||||
public static int SaveSingGeoRuleSet(Config config, SingGeoRuleSet item)
|
||||
{
|
||||
if (Utils.IsNullOrEmpty(item.id))
|
||||
{
|
||||
item.id = Utils.GetGUID(false);
|
||||
}
|
||||
if (SQLiteHelper.Instance.Replace(item) > 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
public static SingGeoRuleSet? GetDefaultSingGeoRuleSet(Config config)
|
||||
{
|
||||
return LazyConfig.Instance.GetSingGeoRuleSets();
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
using System.Net;
|
||||
using System.Globalization;
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
using v2rayN.Models;
|
||||
using v2rayN.Resx;
|
||||
|
@ -56,6 +57,8 @@ namespace v2rayN.Handler
|
|||
|
||||
GenStatistic(singboxConfig);
|
||||
|
||||
GenGeoRuleSetFromJson(singboxConfig);
|
||||
|
||||
ConvertGeo2Ruleset(singboxConfig);
|
||||
|
||||
msg = string.Format(ResUI.SuccessfulConfiguration, "");
|
||||
|
@ -886,9 +889,20 @@ namespace v2rayN.Handler
|
|||
}
|
||||
|
||||
//Add ruleset srs
|
||||
singboxConfig.route.rule_set = [];
|
||||
if (singboxConfig.route.rule_set is null) singboxConfig.route.rule_set = new();
|
||||
foreach (var item in new HashSet<string>(ruleSets))
|
||||
{
|
||||
var exists = false;
|
||||
foreach (var ruleSetItem in singboxConfig.route.rule_set)
|
||||
{
|
||||
if (ruleSetItem?.url?.EndsWith(item + ".srs", true, CultureInfo.InvariantCulture) ?? false)
|
||||
{
|
||||
exists = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (exists) continue;
|
||||
singboxConfig.route.rule_set.Add(new()
|
||||
{
|
||||
type = "remote",
|
||||
|
@ -898,7 +912,27 @@ namespace v2rayN.Handler
|
|||
download_detour = Global.ProxyTag
|
||||
});
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private int GenGeoRuleSetFromJson(SingboxConfig singboxConfig)
|
||||
{
|
||||
var gr = LazyConfig.Instance.GetSingGeoRuleSets();
|
||||
if (gr == null) return -1;
|
||||
var rules = gr.rules;
|
||||
if (gr.rules.Length == 0) return -1;
|
||||
var parsedRules = JsonUtils.Deserialize<List<Ruleset4Sbox>>(rules);
|
||||
if (parsedRules is null) return -1;
|
||||
// manipulate and set defaults
|
||||
for (int i = 0; i < parsedRules.Count; i++)
|
||||
{
|
||||
if (string.IsNullOrEmpty(parsedRules[i].download_detour)) parsedRules[i].download_detour = "proxy";
|
||||
if (string.IsNullOrEmpty(parsedRules[i].format)) parsedRules[i].format = "binary";
|
||||
if (string.IsNullOrEmpty(parsedRules[i].type)) parsedRules[i].type = "remote";
|
||||
}
|
||||
|
||||
if (singboxConfig.route.rule_set is null) singboxConfig.route.rule_set = new();
|
||||
singboxConfig.route.rule_set.AddRange(parsedRules);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@ namespace v2rayN.Handler
|
|||
SQLiteHelper.Instance.CreateTable<RoutingItem>();
|
||||
SQLiteHelper.Instance.CreateTable<ProfileExItem>();
|
||||
SQLiteHelper.Instance.CreateTable<DNSItem>();
|
||||
SQLiteHelper.Instance.CreateTable<SingGeoRuleSet>();
|
||||
}
|
||||
|
||||
#region Config
|
||||
|
@ -160,6 +161,11 @@ namespace v2rayN.Handler
|
|||
return SQLiteHelper.Instance.Table<DNSItem>().FirstOrDefault(it => it.coreType == eCoreType);
|
||||
}
|
||||
|
||||
public SingGeoRuleSet? GetSingGeoRuleSets()
|
||||
{
|
||||
return SQLiteHelper.Instance.Table<SingGeoRuleSet>().FirstOrDefault();
|
||||
}
|
||||
|
||||
#endregion SqliteHelper
|
||||
|
||||
#region Core Type
|
||||
|
|
15
v2rayN/v2rayN/Models/SingGeoRuleSet.cs
Normal file
15
v2rayN/v2rayN/Models/SingGeoRuleSet.cs
Normal file
|
@ -0,0 +1,15 @@
|
|||
using SQLite;
|
||||
|
||||
namespace v2rayN.Models
|
||||
{
|
||||
[Serializable]
|
||||
public class SingGeoRuleSet
|
||||
{
|
||||
[PrimaryKey]
|
||||
public string id { get; set; }
|
||||
|
||||
public string remarks { get; set; }
|
||||
|
||||
public string rules { get; set; }
|
||||
}
|
||||
}
|
788
v2rayN/v2rayN/Resx/ResUI.Designer.cs
generated
788
v2rayN/v2rayN/Resx/ResUI.Designer.cs
generated
File diff suppressed because it is too large
Load diff
|
@ -1003,4 +1003,10 @@
|
|||
<data name="TbSettingsEnableHWA" xml:space="preserve">
|
||||
<value>فعالسازی شتابدهنده سختافزاری (نیاز به راهاندازی مجدد)</value>
|
||||
</data>
|
||||
<data name="TbRoutingTabRuleSet" xml:space="preserve">
|
||||
<value>لیست مجموعه فایل های Geo برای Sing-box</value>
|
||||
</data>
|
||||
<data name="TbSettingSingGeoImportDefRuleSets" xml:space="preserve">
|
||||
<value>برای وارد کردن مجموعه قوانین Geo کلیک کنید</value>
|
||||
</data>
|
||||
</root>
|
|
@ -1207,4 +1207,16 @@
|
|||
<data name="TbSettingsEnableFragment" xml:space="preserve">
|
||||
<value>Enable fragment</value>
|
||||
</data>
|
||||
<data name="TbRoutingTabRuleSet" xml:space="preserve">
|
||||
<value>Sing-box Geo RuleSets</value>
|
||||
</data>
|
||||
<data name="TbSettingsSingGeoRuleSets" xml:space="preserve">
|
||||
<value>Sing-box Geo RuleSet JSON (Array)</value>
|
||||
</data>
|
||||
<data name="TbSettingSingGeoImportDefRuleSets" xml:space="preserve">
|
||||
<value>Click here to import default geo ruleset(s)</value>
|
||||
</data>
|
||||
<data name="TbSingGeoRuleSetDoc" xml:space="preserve">
|
||||
<value>Please fill in RuleSet structure, click to view the document</value>
|
||||
</data>
|
||||
</root>
|
|
@ -1204,4 +1204,16 @@
|
|||
<data name="TbSettingsEnableFragmentTips" xml:space="preserve">
|
||||
<value>使用Xray且非Tun模式启用,和分组前置代理冲突</value>
|
||||
</data>
|
||||
<data name="TbRoutingTabRuleSet" xml:space="preserve">
|
||||
<value>Sing-Box Geo规则集</value>
|
||||
</data>
|
||||
<data name="TbSettingsSingGeoRuleSets" xml:space="preserve">
|
||||
<value>Sing-Box Geo Ruleset JSON(数组)</value>
|
||||
</data>
|
||||
<data name="TbSettingSingGeoImportDefRuleSets" xml:space="preserve">
|
||||
<value>单击此处以导入默认地理规则集</value>
|
||||
</data>
|
||||
<data name="TbSingGeoRuleSetDoc" xml:space="preserve">
|
||||
<value>请填写规则集结构,单击以查看文档</value>
|
||||
</data>
|
||||
</root>
|
|
@ -1177,4 +1177,16 @@
|
|||
<data name="TbSettingsEnableFragmentTips" xml:space="preserve">
|
||||
<value>使用Xray且非Tun模式啟用,和分組前置代理衝突</value>
|
||||
</data>
|
||||
<data name="TbSingGeoRuleSetDoc" xml:space="preserve">
|
||||
<value>請填寫規則集結構,單擊以查看文檔</value>
|
||||
</data>
|
||||
<data name="TbSettingsSingGeoRuleSets" xml:space="preserve">
|
||||
<value>Sing-Box Geo Ruleset JSON(數組)</value>
|
||||
</data>
|
||||
<data name="TbRoutingTabRuleSet" xml:space="preserve">
|
||||
<value>Sing-Box Geo規則集</value>
|
||||
</data>
|
||||
<data name="TbSettingSingGeoImportDefRuleSets" xml:space="preserve">
|
||||
<value>單擊此處以導入默認地理規則集</value>
|
||||
</data>
|
||||
</root>
|
8
v2rayN/v2rayN/Sample/singbox_geo_rulesets
Normal file
8
v2rayN/v2rayN/Sample/singbox_geo_rulesets
Normal file
|
@ -0,0 +1,8 @@
|
|||
[
|
||||
{
|
||||
"tag": "geosite-category-ads-all",
|
||||
"type": "remote",
|
||||
"format": "binary",
|
||||
"url": "https://raw.githubusercontent.com/SagerNet/sing-geosite/rule-set/geosite-category-ads-all.srs"
|
||||
}
|
||||
]
|
|
@ -581,6 +581,7 @@ namespace v2rayN.ViewModels
|
|||
{
|
||||
ConfigHandler.InitBuiltinRouting(_config);
|
||||
ConfigHandler.InitBuiltinDNS(_config);
|
||||
ConfigHandler.InitBuiltinSingGeoRuleSets(_config);
|
||||
_coreHandler = new CoreHandler(_config, UpdateHandler);
|
||||
Locator.CurrentMutable.RegisterLazySingleton(() => _coreHandler, typeof(CoreHandler));
|
||||
|
||||
|
@ -1389,6 +1390,7 @@ namespace v2rayN.ViewModels
|
|||
if (ret == true)
|
||||
{
|
||||
ConfigHandler.InitBuiltinRouting(_config);
|
||||
ConfigHandler.InitBuiltinSingGeoRuleSets(_config);
|
||||
RefreshRoutingsMenu();
|
||||
//RefreshServers();
|
||||
Reload();
|
||||
|
|
|
@ -62,11 +62,15 @@ namespace v2rayN.ViewModels
|
|||
[Reactive]
|
||||
public string BlockIP { get; set; }
|
||||
|
||||
[Reactive]
|
||||
public string SingGeoRuleSets { get; set; }
|
||||
|
||||
public ReactiveCommand<Unit, Unit> RoutingBasicImportRulesCmd { get; }
|
||||
public ReactiveCommand<Unit, Unit> RoutingAdvancedAddCmd { get; }
|
||||
public ReactiveCommand<Unit, Unit> RoutingAdvancedRemoveCmd { get; }
|
||||
public ReactiveCommand<Unit, Unit> RoutingAdvancedSetDefaultCmd { get; }
|
||||
public ReactiveCommand<Unit, Unit> RoutingAdvancedImportRulesCmd { get; }
|
||||
public ReactiveCommand<Unit, Unit> RoutingImportSingGeoDefRuleSetsCmd { get; }
|
||||
|
||||
public ReactiveCommand<Unit, Unit> SaveCmd { get; }
|
||||
public bool IsModified { get; set; }
|
||||
|
@ -81,6 +85,7 @@ namespace v2rayN.ViewModels
|
|||
SelectedSource = new();
|
||||
|
||||
ConfigHandler.InitBuiltinRouting(_config);
|
||||
ConfigHandler.InitBuiltinSingGeoRuleSets(_config);
|
||||
|
||||
enableRoutingAdvanced = _config.routingBasicItem.enableRoutingAdvanced;
|
||||
domainStrategy = _config.routingBasicItem.domainStrategy;
|
||||
|
@ -88,6 +93,8 @@ namespace v2rayN.ViewModels
|
|||
domainStrategy4Singbox = _config.routingBasicItem.domainStrategy4Singbox;
|
||||
|
||||
RefreshRoutingItems();
|
||||
var geoRulesets = LazyConfig.Instance.GetSingGeoRuleSets();
|
||||
if (geoRulesets != null) SingGeoRuleSets = geoRulesets.rules;
|
||||
|
||||
BindingLockedData();
|
||||
|
||||
|
@ -121,6 +128,11 @@ namespace v2rayN.ViewModels
|
|||
RoutingAdvancedImportRules();
|
||||
});
|
||||
|
||||
RoutingImportSingGeoDefRuleSetsCmd = ReactiveCommand.Create(() =>
|
||||
{
|
||||
SingGeoRuleSets = Utils.GetEmbedText(Global.SingboxGeoRuleSetsFileName);
|
||||
});
|
||||
|
||||
SaveCmd = ReactiveCommand.Create(() =>
|
||||
{
|
||||
SaveRouting();
|
||||
|
@ -165,6 +177,13 @@ namespace v2rayN.ViewModels
|
|||
|
||||
ConfigHandler.SaveRoutingItem(_config, _lockedItem);
|
||||
}
|
||||
|
||||
var ruleSet = ConfigHandler.GetDefaultSingGeoRuleSet(_config);
|
||||
if (ruleSet != null)
|
||||
{
|
||||
ruleSet.rules = SingGeoRuleSets;
|
||||
ConfigHandler.SaveSingGeoRuleSet(_config, ruleSet);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion locked
|
||||
|
|
|
@ -155,20 +155,20 @@
|
|||
|
||||
<DockPanel>
|
||||
<TabControl x:Name="tabAdvanced">
|
||||
<TabItem HorizontalAlignment="Left" Header="{x:Static resx:ResUI.TbRoutingTabRuleList}">
|
||||
<TabItem Header="{x:Static resx:ResUI.TbRoutingTabRuleList}">
|
||||
<DataGrid
|
||||
x:Name="lstRoutings"
|
||||
Margin="2,0"
|
||||
AutoGenerateColumns="False"
|
||||
BorderThickness="1"
|
||||
CanUserAddRows="False"
|
||||
CanUserResizeRows="False"
|
||||
CanUserSortColumns="False"
|
||||
EnableRowVirtualization="True"
|
||||
GridLinesVisibility="All"
|
||||
HeadersVisibility="Column"
|
||||
IsReadOnly="True"
|
||||
Style="{StaticResource DefDataGrid}">
|
||||
x:Name="lstRoutings"
|
||||
Margin="2,0"
|
||||
AutoGenerateColumns="False"
|
||||
BorderThickness="1"
|
||||
CanUserAddRows="False"
|
||||
CanUserResizeRows="False"
|
||||
CanUserSortColumns="False"
|
||||
EnableRowVirtualization="True"
|
||||
GridLinesVisibility="All"
|
||||
HeadersVisibility="Column"
|
||||
IsReadOnly="True"
|
||||
Style="{StaticResource DefDataGrid}">
|
||||
<DataGrid.ContextMenu>
|
||||
<ContextMenu Style="{StaticResource DefContextMenu}">
|
||||
<MenuItem
|
||||
|
@ -230,6 +230,41 @@
|
|||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
</TabItem>
|
||||
|
||||
<TabItem Header="{x:Static resx:ResUI.TbRoutingTabRuleSet}">
|
||||
<DockPanel Margin="{StaticResource SettingItemMargin}">
|
||||
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal">
|
||||
<TextBlock
|
||||
Margin="8,0,0,0"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}">
|
||||
<Hyperlink Click="linkSingGeoRuleSetDoc_Click">
|
||||
<TextBlock Text="{x:Static resx:ResUI.TbSingGeoRuleSetDoc}" />
|
||||
</Hyperlink>
|
||||
</TextBlock>
|
||||
<Button
|
||||
x:Name="btnImportDefSingGeoRuleSets"
|
||||
Margin="8,0,0,0"
|
||||
Content="{x:Static resx:ResUI.TbSettingSingGeoImportDefRuleSets}"
|
||||
Cursor="Hand"
|
||||
Style="{StaticResource DefButton}" />
|
||||
</StackPanel>
|
||||
<Grid>
|
||||
<TextBox
|
||||
Name="txtSingGeoRuleSets"
|
||||
Width="940"
|
||||
DockPanel.Dock="Bottom"
|
||||
VerticalAlignment="Stretch"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.TbSettingsSingGeoRuleSets}"
|
||||
AcceptsReturn="True"
|
||||
BorderThickness="1"
|
||||
Style="{StaticResource MaterialDesignOutlinedTextBox}"
|
||||
TextWrapping="Wrap" HorizontalAlignment="Stretch"
|
||||
VerticalScrollBarVisibility="Auto" />
|
||||
</Grid>
|
||||
</DockPanel>
|
||||
</TabItem>
|
||||
</TabControl>
|
||||
|
||||
<TabControl x:Name="tabBasic">
|
||||
|
@ -331,6 +366,41 @@
|
|||
</GroupBox>
|
||||
</Grid>
|
||||
</TabItem>
|
||||
|
||||
<TabItem Header="{x:Static resx:ResUI.TbRoutingTabRuleSet}">
|
||||
<DockPanel Margin="{StaticResource SettingItemMargin}">
|
||||
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal">
|
||||
<TextBlock
|
||||
Margin="8,0,0,0"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}">
|
||||
<Hyperlink Click="linkSingGeoRuleSetDoc_Click">
|
||||
<TextBlock Text="{x:Static resx:ResUI.TbSingGeoRuleSetDoc}" />
|
||||
</Hyperlink>
|
||||
</TextBlock>
|
||||
<Button
|
||||
x:Name="btnImportDefSingGeoRuleSets2"
|
||||
Margin="8,0,0,0"
|
||||
Content="{x:Static resx:ResUI.TbSettingSingGeoImportDefRuleSets}"
|
||||
Cursor="Hand"
|
||||
Style="{StaticResource DefButton}" />
|
||||
</StackPanel>
|
||||
<Grid>
|
||||
<TextBox
|
||||
Name="txtSingGeoRuleSets2"
|
||||
Width="940"
|
||||
DockPanel.Dock="Bottom"
|
||||
VerticalAlignment="Stretch"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.TbSettingsSingGeoRuleSets}"
|
||||
AcceptsReturn="True"
|
||||
BorderThickness="1"
|
||||
Style="{StaticResource MaterialDesignOutlinedTextBox}"
|
||||
TextWrapping="Wrap" HorizontalAlignment="Stretch"
|
||||
VerticalScrollBarVisibility="Auto" />
|
||||
</Grid>
|
||||
</DockPanel>
|
||||
</TabItem>
|
||||
</TabControl>
|
||||
</DockPanel>
|
||||
</DockPanel>
|
||||
|
|
|
@ -60,6 +60,8 @@ namespace v2rayN.Views
|
|||
this.Bind(ViewModel, vm => vm.DirectIP, v => v.txtDirectIP.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.BlockDomain, v => v.txtBlockDomain.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.BlockIP, v => v.txtBlockIP.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SingGeoRuleSets, v => v.txtSingGeoRuleSets.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SingGeoRuleSets, v => v.txtSingGeoRuleSets2.Text).DisposeWith(disposables);
|
||||
|
||||
this.OneWayBind(ViewModel, vm => vm.enableRoutingBasic, v => v.menuRoutingBasic.Visibility).DisposeWith(disposables);
|
||||
this.OneWayBind(ViewModel, vm => vm.enableRoutingAdvanced, v => v.menuRoutingAdvanced.Visibility).DisposeWith(disposables);
|
||||
|
@ -73,6 +75,8 @@ namespace v2rayN.Views
|
|||
this.BindCommand(ViewModel, vm => vm.RoutingAdvancedSetDefaultCmd, v => v.menuRoutingAdvancedSetDefault).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.RoutingAdvancedImportRulesCmd, v => v.menuRoutingAdvancedImportRules).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.RoutingAdvancedImportRulesCmd, v => v.menuRoutingAdvancedImportRules2).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.RoutingImportSingGeoDefRuleSetsCmd, v => v.btnImportDefSingGeoRuleSets).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.RoutingImportSingGeoDefRuleSetsCmd, v => v.btnImportDefSingGeoRuleSets2).DisposeWith(disposables);
|
||||
|
||||
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
|
||||
});
|
||||
|
@ -146,5 +150,10 @@ namespace v2rayN.Views
|
|||
this.Close();
|
||||
}
|
||||
}
|
||||
|
||||
private void linkSingGeoRuleSetDoc_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Utils.ProcessStart("https://sing-box.sagernet.org/configuration/rule-set/");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -30,6 +30,9 @@
|
|||
|
||||
<ItemGroup>
|
||||
<AdditionalFiles Include="app.manifest" />
|
||||
<EmbeddedResource Include="Sample\singbox_geo_rulesets">
|
||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Sample\SingboxSampleOutbound" />
|
||||
<EmbeddedResource Include="Sample\SingboxSampleClientConfig">
|
||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||
|
|
Loading…
Reference in a new issue