Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion BootstrapBlazor.Extensions.slnx
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@
<Project Path="src/components/BootstrapBlazor.OfdReader/BootstrapBlazor.OfdReader.csproj" />
<Project Path="src/components/BootstrapBlazor.OfficeViewer/BootstrapBlazor.OfficeViewer.csproj" />
<Project Path="src/components/BootstrapBlazor.OnScreenKeyboard/BootstrapBlazor.OnScreenKeyboard.csproj" />
<Project Path="src/components/BootstrapBlazor.OpcUa/BootstrapBlazor.OpcUa.csproj" />
<Project Path="src/components/BootstrapBlazor.OpenAI.GPT3/BootstrapBlazor.OpenAI.csproj" />
<Project Path="src/components/BootstrapBlazor.PdfReader/BootstrapBlazor.PdfReader.csproj" />
<Project Path="src/components/BootstrapBlazor.PdfViewer/BootstrapBlazor.PdfViewer.csproj" />
Expand Down Expand Up @@ -103,6 +102,7 @@
<Project Path="src/extensions/BootstrapBlazor.DataAccess.PetaPoco/BootstrapBlazor.DataAccess.PetaPoco.csproj" />
<Project Path="src/extensions/BootstrapBlazor.DataAccess.SqlSugar/BootstrapBlazor.DataAccess.SqlSugar.csproj" />
<Project Path="src/extensions/BootstrapBlazor.OpcDa/BootstrapBlazor.OpcDa.csproj" />
<Project Path="src/extensions/BootstrapBlazor.OpcUa/BootstrapBlazor.OpcUa.csproj" />
</Folder>
<Folder Name="/src/middelware/">
<Project Path="src/middleware/BootstrapBlazor.Middleware/BootstrapBlazor.Middleware.csproj" />
Expand Down
17 changes: 0 additions & 17 deletions src/components/BootstrapBlazor.OpcUa/BootstrapBlazor.OpcUa.csproj

This file was deleted.

42 changes: 42 additions & 0 deletions src/extensions/BootstrapBlazor.OpcUa/BootstrapBlazor.OpcUa.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<Version>10.0.1</Version>
</PropertyGroup>

<PropertyGroup>
<PackageTags>Bootstrap Blazor WebAssembly wasm UI Components Opc Ua Client</PackageTags>
<Description>Bootstrap UI components extensions of OpcUa</Description>
</PropertyGroup>

<PropertyGroup>
<UA6Version>1.5.376.235</UA6Version>
<UA8Version>1.5.378.156</UA8Version>
</PropertyGroup>

<ItemGroup Condition="'$(TargetFramework)' == 'net6.0'">
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="$(NET8Version)" />
<PackageReference Include="OPCFoundation.NetStandard.Opc.Ua.Client" Version="$(UA6Version)" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)' == 'net7.0'">
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="$(NET8Version)" />
<PackageReference Include="OPCFoundation.NetStandard.Opc.Ua.Client" Version="$(UA6Version)" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)' == 'net8.0'">
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="$(NET10Version)" />
<PackageReference Include="OPCFoundation.NetStandard.Opc.Ua.Client" Version="$(UA8Version)" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)' == 'net9.0'">
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="$(NET10Version)" />
<PackageReference Include="OPCFoundation.NetStandard.Opc.Ua.Client" Version="$(UA8Version)" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)' == 'net10.0'">
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="$(NET10Version)" />
<PackageReference Include="OPCFoundation.NetStandard.Opc.Ua.Client" Version="$(UA8Version)" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -1,21 +1,26 @@
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
// Website: https://www.blazor.zone or https://argozhang.github.io/

namespace Microsoft.Extensions.DependencyInjection;

using BootstrapBlazor.OpcUa;

/// <summary>
/// OpcUa 服务扩展类
/// <para lang="zh">OpcUa 服务扩展类</para>
/// <para lang="en">OpcUa service extension class</para>
/// </summary>
public static class ServiceCollectionExtensions
{
/// <summary>
/// 增加 OpcUa 数据服务
/// <para lang="zh">增加 OpcUa 数据服务</para>
/// <para lang="en">Add OpcUa data service</para>
/// </summary>
/// <param name="services"></param>
/// <returns></returns>
public static IServiceCollection AddBootstrapBlazorOpcUaService(this IServiceCollection services)
public static IServiceCollection AddOpcUaServer(this IServiceCollection services)
{
services.AddScoped<IOpcUaServer, OpcUaServer>();
return services;
}
}
32 changes: 32 additions & 0 deletions src/extensions/BootstrapBlazor.OpcUa/Guard.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
// Website: https://www.blazor.zone or https://argozhang.github.io/

namespace BootstrapBlazor.OpcUa;

static class Guard
{
public static void ThrowIfDisposed(bool disposed, object instance)
{
#if NET6_0
if (disposed)
{
throw new ObjectDisposedException(instance.GetType().FullName);
}
#else
ObjectDisposedException.ThrowIf(disposed, instance.GetType());
#endif
}

public static void ThrowIfNullOrWhiteSpace(string? value, string paramName)
{
#if NET8_0_OR_GREATER
ArgumentException.ThrowIfNullOrWhiteSpace(value, paramName);
#else
if (string.IsNullOrWhiteSpace(value))
{
throw new ArgumentException($"'{paramName}' cannot be null or whitespace.", paramName);
}
#endif
}
}
66 changes: 66 additions & 0 deletions src/extensions/BootstrapBlazor.OpcUa/IOpcUaServer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
// Website: https://www.blazor.zone or https://argozhang.github.io/

namespace BootstrapBlazor.OpcUa;

/// <summary>
/// <para lang="zh">OPC UA 客户端接口</para>
/// <para lang="en">OPC UA client interface</para>
/// </summary>
public interface IOpcUaServer : IAsyncDisposable
{
/// <summary>
/// <para lang="zh">获得当前是否已连接</para>
/// <para lang="en">Gets whether the client is connected</para>
/// </summary>
bool IsConnected { get; }

/// <summary>
/// <para lang="zh">获得当前端点地址</para>
/// <para lang="en">Gets the current endpoint URL</para>
/// </summary>
string? EndpointUrl { get; }

/// <summary>
/// <para lang="zh">连接 OPC UA 服务器</para>
/// <para lang="en">Connects to an OPC UA server</para>
/// </summary>
Task<bool> ConnectAsync(string endpointUrl, OpcUaConnectionOptions? options = null, CancellationToken cancellationToken = default);

/// <summary>
/// <para lang="zh">断开当前连接</para>
/// <para lang="en">Disconnects the current session</para>
/// </summary>
Task DisconnectAsync(CancellationToken cancellationToken = default);

/// <summary>
/// <para lang="zh">读取节点值</para>
/// <para lang="en">Reads node values</para>
/// </summary>
Task<IReadOnlyList<OpcUaReadItem>> ReadAsync(IEnumerable<string> nodeIds, CancellationToken cancellationToken = default);

/// <summary>
/// <para lang="zh">写入节点值</para>
/// <para lang="en">Writes node values</para>
/// </summary>
Task<IReadOnlyList<OpcUaWriteItem>> WriteAsync(IEnumerable<OpcUaWriteItem> items, CancellationToken cancellationToken = default);

/// <summary>
/// <para lang="zh">浏览节点</para>
/// <para lang="en">Browses a node</para>
/// </summary>
Task<IReadOnlyList<OpcUaBrowseElement>> BrowseAsync(string nodeId, OpcUaBrowseOptions? options = null, CancellationToken cancellationToken = default);

/// <summary>
/// <para lang="zh">创建订阅</para>
/// <para lang="en">Creates a subscription</para>
/// </summary>
Task<IOpcUaSubscription> CreateSubscriptionAsync(string name, int publishingInterval = 1000, bool active = true, CancellationToken cancellationToken = default);

/// <summary>
/// <para lang="zh">取消订阅</para>
/// <para lang="en">Cancels a subscription</para>
/// </summary>
Task CancelSubscriptionAsync(IOpcUaSubscription subscription, CancellationToken cancellationToken = default);
}
36 changes: 36 additions & 0 deletions src/extensions/BootstrapBlazor.OpcUa/IOpcUaSubscription.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
// Website: https://www.blazor.zone or https://argozhang.github.io/

namespace BootstrapBlazor.OpcUa;

/// <summary>
/// <para lang="zh">OPC UA 订阅接口</para>
/// <para lang="en">OPC UA subscription interface</para>
/// </summary>
public interface IOpcUaSubscription
{
/// <summary>
/// <para lang="zh">获得 订阅名称</para>
/// <para lang="en">Gets the subscription name</para>
/// </summary>
string Name { get; }

/// <summary>
/// <para lang="zh">获得/设置 是否保留上一次的值</para>
/// <para lang="en">Gets or sets whether to retain the previous value</para>
/// </summary>
bool KeepLastValue { get; set; }

/// <summary>
/// <para lang="zh">获得/设置 数据变化回调</para>
/// <para lang="en">Gets or sets the data change callback</para>
/// </summary>
Action<IReadOnlyList<OpcUaReadItem>>? DataChanged { get; set; }

/// <summary>
/// <para lang="zh">增加监控节点</para>
/// <para lang="en">Adds monitored nodes</para>
/// </summary>
Task AddItemsAsync(IEnumerable<string> nodeIds, int samplingInterval = -1, CancellationToken cancellationToken = default);
}
19 changes: 19 additions & 0 deletions src/extensions/BootstrapBlazor.OpcUa/OpcUaBrowseElement.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
// Website: https://www.blazor.zone or https://argozhang.github.io/

using Opc.Ua;

namespace BootstrapBlazor.OpcUa;

/// <summary>
/// <para lang="zh">OPC UA 浏览节点</para>
/// <para lang="en">OPC UA browsed node</para>
/// </summary>
public sealed record OpcUaBrowseElement(
string NodeId,
string BrowseName,
string DisplayName,
NodeClass NodeClass,
string ReferenceTypeId,
string? TypeDefinitionId);
44 changes: 44 additions & 0 deletions src/extensions/BootstrapBlazor.OpcUa/OpcUaBrowseOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
// Website: https://www.blazor.zone or https://argozhang.github.io/

using Opc.Ua;

namespace BootstrapBlazor.OpcUa;

/// <summary>
/// <para lang="zh">OPC UA 节点浏览配置</para>
/// <para lang="en">OPC UA node browse options</para>
/// </summary>
public sealed class OpcUaBrowseOptions
{
/// <summary>
/// <para lang="zh">获得/设置 每个节点最多返回的引用数量,零表示由服务器决定</para>
/// <para lang="en">Gets or sets the maximum references returned per node; zero lets the server decide</para>
/// </summary>
public uint MaxReferencesReturned { get; set; }

/// <summary>
/// <para lang="zh">获得/设置 浏览方向</para>
/// <para lang="en">Gets or sets the browse direction</para>
/// </summary>
public BrowseDirection BrowseDirection { get; set; } = BrowseDirection.Forward;

/// <summary>
/// <para lang="zh">获得/设置 引用类型</para>
/// <para lang="en">Gets or sets the reference type</para>
/// </summary>
public NodeId ReferenceTypeId { get; set; } = ReferenceTypeIds.HierarchicalReferences;

/// <summary>
/// <para lang="zh">获得/设置 是否包含引用类型的子类型</para>
/// <para lang="en">Gets or sets whether reference subtypes are included</para>
/// </summary>
public bool IncludeSubtypes { get; set; } = true;

/// <summary>
/// <para lang="zh">获得/设置 节点类型掩码</para>
/// <para lang="en">Gets or sets the node class mask</para>
/// </summary>
public uint NodeClassMask { get; set; } = (uint)(NodeClass.Object | NodeClass.Variable | NodeClass.Method);
}
62 changes: 62 additions & 0 deletions src/extensions/BootstrapBlazor.OpcUa/OpcUaConnectionOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
// Website: https://www.blazor.zone or https://argozhang.github.io/

using Opc.Ua;

namespace BootstrapBlazor.OpcUa;

/// <summary>
/// <para lang="zh">OPC UA 连接配置</para>
/// <para lang="en">OPC UA connection options</para>
/// </summary>
public sealed class OpcUaConnectionOptions
{
/// <summary>
/// <para lang="zh">获得/设置 应用名称</para>
/// <para lang="en">Gets or sets the application name</para>
/// </summary>
public string ApplicationName { get; set; } = "BootstrapBlazor OpcUa Client";

/// <summary>
/// <para lang="zh">获得/设置 会话名称</para>
/// <para lang="en">Gets or sets the session name</para>
/// </summary>
public string SessionName { get; set; } = "BootstrapBlazor.OpcUa";

/// <summary>
/// <para lang="zh">获得/设置 会话超时时间,单位毫秒</para>
/// <para lang="en">Gets or sets the session timeout in milliseconds</para>
/// </summary>
public uint SessionTimeout { get; set; } = 60000;

/// <summary>
/// <para lang="zh">获得/设置 操作超时时间,单位毫秒</para>
/// <para lang="en">Gets or sets the operation timeout in milliseconds</para>
/// </summary>
public int OperationTimeout { get; set; } = 15000;

/// <summary>
/// <para lang="zh">获得/设置 是否选择安全端点</para>
/// <para lang="en">Gets or sets whether to select a secure endpoint</para>
/// </summary>
public bool UseSecurity { get; set; }

/// <summary>
/// <para lang="zh">获得/设置 用户身份,默认使用匿名身份</para>
/// <para lang="en">Gets or sets the user identity; anonymous identity is used by default</para>
/// </summary>
public IUserIdentity? Identity { get; set; }

/// <summary>
/// <para lang="zh">获得/设置 首选区域</para>
/// <para lang="en">Gets or sets the preferred locales</para>
/// </summary>
public IList<string>? PreferredLocales { get; set; }

/// <summary>
/// <para lang="zh">获得/设置 应用配置,安全连接应提供包含证书配置的实例</para>
/// <para lang="en">Gets or sets the application configuration; secure connections should provide certificate settings</para>
/// </summary>
public ApplicationConfiguration? Configuration { get; set; }
}
26 changes: 26 additions & 0 deletions src/extensions/BootstrapBlazor.OpcUa/OpcUaReadItem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
// Website: https://www.blazor.zone or https://argozhang.github.io/

using Opc.Ua;

namespace BootstrapBlazor.OpcUa;

/// <summary>
/// <para lang="zh">OPC UA 节点读取结果</para>
/// <para lang="en">OPC UA node read result</para>
/// </summary>
public sealed record OpcUaReadItem(string NodeId, object? Value, StatusCode StatusCode, DateTime SourceTimestamp, DateTime ServerTimestamp)
{
/// <summary>
/// <para lang="zh">获得状态是否正常</para>
/// <para lang="en">Gets whether the status is good</para>
/// </summary>
public bool IsGood => Opc.Ua.StatusCode.IsGood(StatusCode);

/// <summary>
/// <para lang="zh">获得上一次的值</para>
/// <para lang="en">Gets the previous value</para>
/// </summary>
public object? LastValue { get; init; }
}
Loading
Loading