mirror of
https://github.com/BeyondDimension/SteamTools.git
synced 2026-10-28 14:08:16 +08:00
⬆️ SDK 1.23.10329.11240 (XmlnsDefinition) & IPC Misc
This commit is contained in:
+1
-1
Submodule ref/DirectoryPackages updated: 97814a26b0...27d1ee5a5f
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -7,18 +7,21 @@ public abstract class IPCServiceImpl<TPacket> : IPCService<TPacket>, IDisposable
|
||||
|
||||
public async ValueTask<int> RunAsync(string? pipeName)
|
||||
{
|
||||
if (pipeClient != null)
|
||||
if (pipeClient != null) // 此函数应仅调用一次
|
||||
return (int)IPCExitCode.Ok;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(pipeName))
|
||||
return (int)IPCExitCode.EmptyPipeName;
|
||||
|
||||
// 命名管道实现 IPC
|
||||
pipeClient = new NamedPipeClientStream(".", pipeName, PipeDirection.InOut, PipeOptions.None, TokenImpersonationLevel.Impersonation);
|
||||
|
||||
try
|
||||
{
|
||||
// 尝试在 45 秒内连接主进程
|
||||
pipeClient.Connect(TimeSpan.FromSeconds(45d));
|
||||
// https://blog.lindexi.com/post/dotnet-%E4%BD%BF%E7%94%A8-NamedPipeClientStream-%E8%BF%9E%E6%8E%A5%E4%B8%80%E4%B8%AA%E4%B8%8D%E5%AD%98%E5%9C%A8%E7%AE%A1%E9%81%93%E6%9C%8D%E5%8A%A1%E5%90%8D%E5%B0%86%E4%B8%8D%E6%96%AD%E7%A9%BA%E8%B7%91-CPU-%E8%B5%84%E6%BA%90.html
|
||||
// 尝试在 15 秒内连接主进程
|
||||
const int timeout_connect = 15000;
|
||||
await pipeClient.ConnectAsync(timeout_connect);
|
||||
}
|
||||
catch (TimeoutException)
|
||||
{
|
||||
@@ -27,7 +30,7 @@ public abstract class IPCServiceImpl<TPacket> : IPCService<TPacket>, IDisposable
|
||||
|
||||
while (!disposedValue)
|
||||
{
|
||||
var packet = ReadBytes(pipeClient);
|
||||
var packet = Read(pipeClient);
|
||||
if (packet != default)
|
||||
{
|
||||
var exitCode = await HandleCommand(packet);
|
||||
@@ -46,14 +49,45 @@ public abstract class IPCServiceImpl<TPacket> : IPCService<TPacket>, IDisposable
|
||||
Write(pipeClient, packet);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理数据包
|
||||
/// </summary>
|
||||
/// <param name="packet"></param>
|
||||
/// <returns></returns>
|
||||
protected virtual ValueTask<int?> HandleCommand(TPacket packet)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
protected abstract TPacket? ReadBytes(Stream stream);
|
||||
/// <summary>
|
||||
/// 从流中读取一个数据包
|
||||
/// </summary>
|
||||
/// <param name="stream"></param>
|
||||
/// <returns></returns>
|
||||
protected virtual TPacket? Read(Stream stream)
|
||||
{
|
||||
Span<byte> inBuffer = stackalloc byte[sizeof(int)];
|
||||
stream.Read(inBuffer);
|
||||
var len = BitConverter.ToInt32(inBuffer);
|
||||
if (len <= 0) return default;
|
||||
inBuffer = stackalloc byte[len];
|
||||
stream.Read(inBuffer);
|
||||
var obj = MemoryPackSerializer.Deserialize<TPacket>(inBuffer);
|
||||
return obj;
|
||||
}
|
||||
|
||||
protected abstract void Write(Stream stream, TPacket packet);
|
||||
/// <summary>
|
||||
/// 将一个数据包写入流中
|
||||
/// </summary>
|
||||
/// <param name="stream"></param>
|
||||
/// <param name="packet"></param>
|
||||
protected virtual void Write(Stream stream, TPacket packet)
|
||||
{
|
||||
byte[] outBuffer = MemoryPackSerializer.Serialize(packet);
|
||||
stream.Write(BitConverter.GetBytes(outBuffer.Length));
|
||||
stream.Write(outBuffer);
|
||||
stream.Flush();
|
||||
}
|
||||
|
||||
void Dispose(bool disposing)
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
namespace BD.WTTS.Services;
|
||||
|
||||
public interface IPCService<TPacket> where TPacket : class
|
||||
public interface IPCService<TPacket> : IDisposable where TPacket : class
|
||||
{
|
||||
/// <summary>
|
||||
/// 启动 IPC 服务
|
||||
|
||||
@@ -24,4 +24,19 @@ public enum ReverseProxyCommand : byte
|
||||
/// 获取当前流量统计
|
||||
/// </summary>
|
||||
GetFlowStatistics,
|
||||
|
||||
/// <summary>
|
||||
/// 调用 UI 进程通知显示 DNS 错误
|
||||
/// </summary>
|
||||
NotifyDNSError,
|
||||
|
||||
/// <summary>
|
||||
/// 热重载配置文件
|
||||
/// </summary>
|
||||
HotReloadConfig,
|
||||
|
||||
/// <summary>
|
||||
/// 启动反向代理控制台结果
|
||||
/// </summary>
|
||||
StartResult,
|
||||
}
|
||||
|
||||
@@ -8,36 +8,8 @@ namespace BD.WTTS.Models;
|
||||
[MemoryPackUnion(1, typeof(FlowStatistics))]
|
||||
public partial interface IReverseProxyPacket
|
||||
{
|
||||
/// <summary>
|
||||
/// 从流中读取一个 <see cref="IReverseProxyPacket"/>
|
||||
/// </summary>
|
||||
/// <param name="stream"></param>
|
||||
/// <returns></returns>
|
||||
static IReverseProxyPacket? ReadBytes(Stream stream)
|
||||
{
|
||||
Span<byte> inBuffer = stackalloc byte[sizeof(int)];
|
||||
stream.Read(inBuffer);
|
||||
var len = BitConverter.ToInt32(inBuffer);
|
||||
if (len <= 0) return default;
|
||||
inBuffer = stackalloc byte[len];
|
||||
stream.Read(inBuffer);
|
||||
var obj = MemoryPackSerializer.Deserialize<IReverseProxyPacket>(inBuffer);
|
||||
return obj;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将一个 <see cref="IReverseProxyPacket"/> 写入流中
|
||||
/// </summary>
|
||||
/// <param name="stream"></param>
|
||||
/// <param name="packet"></param>
|
||||
static void Write(Stream stream, IReverseProxyPacket packet)
|
||||
{
|
||||
byte[] outBuffer = MemoryPackSerializer.Serialize(packet);
|
||||
stream.Write(BitConverter.GetBytes(outBuffer.Length));
|
||||
stream.Write(outBuffer);
|
||||
stream.Flush();
|
||||
}
|
||||
}
|
||||
|
||||
[MemoryPackable]
|
||||
public sealed partial record ReverseProxyPacket(ReverseProxyCommand Command) : IReverseProxyPacket { }
|
||||
public sealed partial record ReverseProxyPacket(ReverseProxyCommand Command, string? Data) : IReverseProxyPacket { }
|
||||
@@ -1,49 +1,24 @@
|
||||
if (!args.Any()) return (int)ExitCode.EmptyArrayArgs;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
if (!args.Any())
|
||||
return (int)IPCExitCode.EmptyArrayArgs;
|
||||
var pipeName = args[0];
|
||||
if (string.IsNullOrWhiteSpace(pipeName)) return (int)ExitCode.EmptyPipeName;
|
||||
if (string.IsNullOrWhiteSpace(pipeName))
|
||||
return (int)IPCExitCode.EmptyPipeName;
|
||||
|
||||
using var pipeClient = new NamedPipeClientStream(".", pipeName, PipeDirection.InOut, PipeOptions.None, TokenImpersonationLevel.Impersonation);
|
||||
Ioc.ConfigureServices(ConfigureServices);
|
||||
|
||||
try
|
||||
static void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
// 尝试在 45 秒内连接主进程
|
||||
pipeClient.Connect(TimeSpan.FromSeconds(45d));
|
||||
}
|
||||
catch (TimeoutException)
|
||||
{
|
||||
return (int)ExitCode.ConnectServerTimeout;
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
var packet = IReverseProxyPacket.ReadBytes(pipeClient);
|
||||
if (packet != default)
|
||||
services.AddLogging(l =>
|
||||
{
|
||||
if (packet is ReverseProxyPacket packet1)
|
||||
{
|
||||
switch (packet1.Command)
|
||||
{
|
||||
case ReverseProxyCommand.Exit:
|
||||
goto exit;
|
||||
case ReverseProxyCommand.GetFlowStatistics:
|
||||
FlowStatistics flowStatistics = null!;
|
||||
IReverseProxyPacket.Write(pipeClient, flowStatistics);
|
||||
break;
|
||||
case ReverseProxyCommand.Start:
|
||||
break;
|
||||
case ReverseProxyCommand.Stop:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
l.AddConsole();
|
||||
});
|
||||
|
||||
services.AddReverseProxyService();
|
||||
services.AddSingleton<IPCService, IPCServiceImpl>();
|
||||
}
|
||||
|
||||
exit: return (int)ExitCode.Ok;
|
||||
|
||||
enum ExitCode
|
||||
{
|
||||
Ok = 0,
|
||||
EmptyArrayArgs = 4001,
|
||||
EmptyPipeName,
|
||||
ConnectServerTimeout,
|
||||
}
|
||||
using var ipc = IPCService.Instance;
|
||||
var exitCode = await ipc.RunAsync(pipeName);
|
||||
return exitCode;
|
||||
+4
-2
@@ -9,11 +9,13 @@ namespace BD.WTTS.Services.Implementation;
|
||||
sealed class DomainResolver : IDomainResolver
|
||||
{
|
||||
readonly IReverseProxyConfig reverseProxyConfig;
|
||||
readonly IPCService ipc;
|
||||
|
||||
bool isIpv6 = false;
|
||||
|
||||
public DomainResolver(IReverseProxyConfig reverseProxyConfig)
|
||||
public DomainResolver(IPCService ipc, IReverseProxyConfig reverseProxyConfig)
|
||||
{
|
||||
this.ipc = ipc;
|
||||
this.reverseProxyConfig = reverseProxyConfig;
|
||||
}
|
||||
|
||||
@@ -34,7 +36,7 @@ sealed class DomainResolver : IDomainResolver
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
IPCService.Instance.NotifyDNSError(ex);
|
||||
ipc.Send(ReverseProxyCommand.NotifyDNSError, ex.Message);
|
||||
//INotificationService.Instance.Notify(AppResources.CommunityFix_DNSErrorNotify + Environment.NewLine + "Exception Message :" + ex.Message, NotificationType.Message);
|
||||
throw;
|
||||
}
|
||||
|
||||
+15
-14
@@ -2,21 +2,31 @@ namespace BD.WTTS.Services.Implementation;
|
||||
|
||||
sealed class IPCServiceImpl : IPCServiceImpl<IReverseProxyPacket>, IPCService
|
||||
{
|
||||
protected override ValueTask<int?> HandleCommand(IReverseProxyPacket packet)
|
||||
public IPCServiceImpl()
|
||||
{
|
||||
// 保持无依赖注入的空构造函数
|
||||
}
|
||||
|
||||
protected override async ValueTask<int?> HandleCommand(IReverseProxyPacket packet)
|
||||
{
|
||||
if (packet is ReverseProxyPacket packet1)
|
||||
{
|
||||
switch (packet1.Command)
|
||||
{
|
||||
case ReverseProxyCommand.Exit:
|
||||
return new ValueTask<int?>((int)IPCExitCode.Ok);
|
||||
return (int)IPCExitCode.Ok;
|
||||
case ReverseProxyCommand.GetFlowStatistics:
|
||||
FlowStatistics flowStatistics = null!;
|
||||
Send(flowStatistics);
|
||||
break;
|
||||
case ReverseProxyCommand.Start:
|
||||
var startResult = await IReverseProxyService.Instance.StartProxyAsync();
|
||||
Send(ReverseProxyCommand.StartResult, startResult ? null : "Startup failed.");
|
||||
break;
|
||||
case ReverseProxyCommand.Stop:
|
||||
await IReverseProxyService.Instance.StopProxyAsync();
|
||||
break;
|
||||
case ReverseProxyCommand.HotReloadConfig:
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -24,18 +34,9 @@ sealed class IPCServiceImpl : IPCServiceImpl<IReverseProxyPacket>, IPCService
|
||||
return default;
|
||||
}
|
||||
|
||||
public void NotifyDNSError(Exception ex)
|
||||
public void Send(ReverseProxyCommand command, string? data = null)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected override IReverseProxyPacket? ReadBytes(Stream stream)
|
||||
{
|
||||
return IReverseProxyPacket.ReadBytes(stream);
|
||||
}
|
||||
|
||||
protected override void Write(Stream stream, IReverseProxyPacket packet)
|
||||
{
|
||||
IReverseProxyPacket.Write(stream, packet);
|
||||
ReverseProxyPacket packet = new(command, data);
|
||||
Send(packet);
|
||||
}
|
||||
}
|
||||
|
||||
+1
@@ -28,6 +28,7 @@ partial class YarpReverseProxyServiceImpl
|
||||
services.AddPacketIntercept();
|
||||
}
|
||||
#endif
|
||||
services.AddSingleton<IPCService>(_ => ipc);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
|
||||
+3
@@ -11,11 +11,14 @@ sealed partial class YarpReverseProxyServiceImpl : ReverseProxyServiceImpl, IRev
|
||||
static readonly string RootPath = Path.Combine(IOPath.AppDataDirectory, "Yarp");
|
||||
|
||||
WebApplication? app;
|
||||
readonly IPCService ipc;
|
||||
|
||||
public YarpReverseProxyServiceImpl(
|
||||
IPCService ipc,
|
||||
IDnsAnalysisService dnsAnalysis,
|
||||
ICertificateManager certificateManager) : base(dnsAnalysis)
|
||||
{
|
||||
this.ipc = ipc;
|
||||
CertificateManager = certificateManager;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,5 +4,10 @@ public interface IPCService : IPCService<IReverseProxyPacket>
|
||||
{
|
||||
static IPCService Instance => Ioc.Get<IPCService>();
|
||||
|
||||
void NotifyDNSError(Exception ex);
|
||||
/// <summary>
|
||||
/// 给主进程发送指令以及可选的附加消息
|
||||
/// </summary>
|
||||
/// <param name="command"></param>
|
||||
/// <param name="data"></param>
|
||||
void Send(ReverseProxyCommand command, string? data = null);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
namespace BD.WTTS.Models.Abstractions;
|
||||
|
||||
/// <summary>
|
||||
/// 操作结果信息类,对操作结果进行封装
|
||||
/// </summary>
|
||||
public interface IOperationResult
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取或设置 操作结果类型
|
||||
/// </summary>
|
||||
OperationResultType ResultType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置 操作返回信息
|
||||
/// </summary>
|
||||
string Message { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置 操作返回的日志消息,用于记录日志
|
||||
/// </summary>
|
||||
string LogMessage { get; set; }
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IOperationResult"/>
|
||||
public interface IOperationResult<T> : IOperationResult
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取或设置 操作结果附加信息
|
||||
/// </summary>
|
||||
T AppendData { get; set; }
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IOperationResult{T}"/>
|
||||
public abstract class OperationResultBase<T> : IOperationResult<T>
|
||||
{
|
||||
#region 构造函数
|
||||
|
||||
public OperationResultBase()
|
||||
{
|
||||
ResultType = OperationResultType.Error;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化一个 操作结果信息类 的新实例
|
||||
/// </summary>
|
||||
/// <param name="resultType">操作结果类型</param>
|
||||
public OperationResultBase(OperationResultType resultType)
|
||||
{
|
||||
ResultType = resultType;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化一个 定义返回消息的操作结果信息类 的新实例
|
||||
/// </summary>
|
||||
/// <param name="resultType">操作结果类型</param>
|
||||
/// <param name="message">返回消息</param>
|
||||
public OperationResultBase(OperationResultType resultType, string message)
|
||||
: this(resultType)
|
||||
{
|
||||
Message = message;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化一个 定义返回消息与附加数据的操作结果信息类 的新实例
|
||||
/// </summary>
|
||||
/// <param name="resultType">操作结果类型</param>
|
||||
/// <param name="message">返回消息</param>
|
||||
/// <param name="appendData">返回数据</param>
|
||||
public OperationResultBase(OperationResultType resultType, string message, T? appendData)
|
||||
: this(resultType, message)
|
||||
{
|
||||
_AppendData = appendData;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化一个 定义返回消息与日志消息的操作结果信息类 的新实例
|
||||
/// </summary>
|
||||
/// <param name="resultType">操作结果类型</param>
|
||||
/// <param name="message">返回消息</param>
|
||||
/// <param name="logMessage">日志记录消息</param>
|
||||
public OperationResultBase(OperationResultType resultType, string message, string logMessage)
|
||||
: this(resultType, message)
|
||||
{
|
||||
LogMessage = logMessage;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化一个 定义返回消息、日志消息与附加数据的操作结果信息类 的新实例
|
||||
/// </summary>
|
||||
/// <param name="resultType">操作结果类型</param>
|
||||
/// <param name="message">返回消息</param>
|
||||
/// <param name="logMessage">日志记录消息</param>
|
||||
/// <param name="appendData">返回数据</param>
|
||||
public OperationResultBase(OperationResultType resultType, string message, string logMessage, T? appendData)
|
||||
: this(resultType, message, logMessage)
|
||||
{
|
||||
_AppendData = appendData;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 属性
|
||||
|
||||
public OperationResultType ResultType { get; set; }
|
||||
|
||||
public string Message { get; set; } = string.Empty;
|
||||
|
||||
public string LogMessage { get; set; } = string.Empty;
|
||||
|
||||
protected T? _AppendData;
|
||||
|
||||
public virtual T AppendData
|
||||
{
|
||||
get
|
||||
{
|
||||
_AppendData ??= Activator.CreateInstance<T>();
|
||||
return _AppendData;
|
||||
}
|
||||
set => _AppendData = value;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -1,127 +1,5 @@
|
||||
namespace BD.WTTS.Models;
|
||||
|
||||
/// <summary>
|
||||
/// 操作结果信息类,对操作结果进行封装
|
||||
/// </summary>
|
||||
public interface IOperationResult
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取或设置 操作结果类型
|
||||
/// </summary>
|
||||
OperationResultType ResultType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置 操作返回信息
|
||||
/// </summary>
|
||||
string Message { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置 操作返回的日志消息,用于记录日志
|
||||
/// </summary>
|
||||
string LogMessage { get; set; }
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IOperationResult"/>
|
||||
public interface IOperationResult<T> : IOperationResult
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取或设置 操作结果附加信息
|
||||
/// </summary>
|
||||
T AppendData { get; set; }
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IOperationResult{T}"/>
|
||||
public abstract class OperationResultBase<T> : IOperationResult<T>
|
||||
{
|
||||
#region 构造函数
|
||||
|
||||
public OperationResultBase()
|
||||
{
|
||||
ResultType = OperationResultType.Error;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化一个 操作结果信息类 的新实例
|
||||
/// </summary>
|
||||
/// <param name="resultType">操作结果类型</param>
|
||||
public OperationResultBase(OperationResultType resultType)
|
||||
{
|
||||
ResultType = resultType;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化一个 定义返回消息的操作结果信息类 的新实例
|
||||
/// </summary>
|
||||
/// <param name="resultType">操作结果类型</param>
|
||||
/// <param name="message">返回消息</param>
|
||||
public OperationResultBase(OperationResultType resultType, string message)
|
||||
: this(resultType)
|
||||
{
|
||||
Message = message;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化一个 定义返回消息与附加数据的操作结果信息类 的新实例
|
||||
/// </summary>
|
||||
/// <param name="resultType">操作结果类型</param>
|
||||
/// <param name="message">返回消息</param>
|
||||
/// <param name="appendData">返回数据</param>
|
||||
public OperationResultBase(OperationResultType resultType, string message, T? appendData)
|
||||
: this(resultType, message)
|
||||
{
|
||||
_AppendData = appendData;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化一个 定义返回消息与日志消息的操作结果信息类 的新实例
|
||||
/// </summary>
|
||||
/// <param name="resultType">操作结果类型</param>
|
||||
/// <param name="message">返回消息</param>
|
||||
/// <param name="logMessage">日志记录消息</param>
|
||||
public OperationResultBase(OperationResultType resultType, string message, string logMessage)
|
||||
: this(resultType, message)
|
||||
{
|
||||
LogMessage = logMessage;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化一个 定义返回消息、日志消息与附加数据的操作结果信息类 的新实例
|
||||
/// </summary>
|
||||
/// <param name="resultType">操作结果类型</param>
|
||||
/// <param name="message">返回消息</param>
|
||||
/// <param name="logMessage">日志记录消息</param>
|
||||
/// <param name="appendData">返回数据</param>
|
||||
public OperationResultBase(OperationResultType resultType, string message, string logMessage, T? appendData)
|
||||
: this(resultType, message, logMessage)
|
||||
{
|
||||
_AppendData = appendData;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 属性
|
||||
|
||||
public OperationResultType ResultType { get; set; }
|
||||
|
||||
public string Message { get; set; } = string.Empty;
|
||||
|
||||
public string LogMessage { get; set; } = string.Empty;
|
||||
|
||||
protected T? _AppendData;
|
||||
|
||||
public virtual T AppendData
|
||||
{
|
||||
get
|
||||
{
|
||||
_AppendData ??= Activator.CreateInstance<T>();
|
||||
return _AppendData;
|
||||
}
|
||||
set => _AppendData = value;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="OperationResultBase{T}"/>
|
||||
public class OperationResult : OperationResultBase<object>
|
||||
{
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
#if (WINDOWS || MACCATALYST || MACOS || LINUX) && !(IOS || ANDROID)
|
||||
using XmlnsDefinition = Avalonia.Metadata.XmlnsDefinitionAttribute;
|
||||
|
||||
// steampp
|
||||
[assembly: XmlnsDefinition("https://steampp.net/ui", "BD.WTTS.Models")]
|
||||
[assembly: XmlnsDefinition("https://steampp.net/ui", "BD.WTTS.Models.Abstractions")]
|
||||
[assembly: XmlnsDefinition("https://steampp.net/ui", "BD.WTTS.UI.ViewModels")]
|
||||
[assembly: XmlnsDefinition("https://steampp.net/ui", "BD.WTTS.UI.ViewModels.Abstractions")]
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user