Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
0da7a6b
Reorganizes imports and adds new API controllers
May 22, 2026
8a1b217
Adds REST controllers for devices and phasors.
May 22, 2026
fff5e7e
Adds the DeviceWithPhasors class to the model.
May 22, 2026
9cfc797
Translates DeviceWithPhasors comments into English
May 22, 2026
9496e3b
Merge branch 'master' into add-new-controllers-to-custom-apismaster
eduardocordova21 May 22, 2026
8df2724
Simplified Phasor Query and XML Comment Adjustment
May 22, 2026
71a7cbf
Merge branch 'add-new-controllers-to-custom-apismaster' of https://gi…
May 22, 2026
64f9804
Merge branch 'master' into add-new-controllers-to-custom-apismaster
eduardocordova21 May 22, 2026
7754b1e
Merge branch 'master' into add-new-controllers-to-custom-apismaster
eduardocordova21 May 25, 2026
c398055
Added IsConcentrator column to device CSV
eduardocordova21 May 26, 2026
eea8dce
Added device and phasor upsert endpoints
eduardocordova21 Jun 1, 2026
0824091
Replace DeviceDetail with Device in controllers and models
eduardocordova21 Jun 5, 2026
ab64f3f
Adds automatic measurement creation/update
eduardocordova21 Jun 8, 2026
923ca55
Merge branch 'master' into add-new-controllers-to-custom-apismaster
ritchiecarroll Jun 8, 2026
47641eb
Importing Devices with Enhanced Metadata
eduardocordova21 Jun 9, 2026
882e6af
Merge branch 'add-new-controllers-to-custom-apismaster' of https://gi…
eduardocordova21 Jun 9, 2026
63df689
Adds Swagger support for openPDC REST APIs.
eduardocordova21 Jun 9, 2026
5918fa8
Enables anonymous access to /swagger via configuration
eduardocordova21 Jun 9, 2026
bad0e13
Add Swashbuckle.Core.dll to the installer and generate ngen
eduardocordova21 Jun 9, 2026
17b5eae
Standardizes PointTags and optimizes signal type queries.
eduardocordova21 Jun 10, 2026
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 Source/Applications/openPDC/openPDC/App.config
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
<add name="BootstrapTheme" value="Content/bootstrap-theme.min.css" description="Path to Bootstrap CSS to use for rendering styles." encrypted="false"/>
<add name="AuthenticationSchemes" value="Ntlm, Basic" description="Comma separated list of authentication schemes to use for clients accessing the hosted web server, e.g., Basic or NTLM." encrypted="false"/>
<add name="AuthFailureRedirectResourceExpression" value="^/$|^/.+\.cshtml$|^/.+\.vbhtml$|^/grafana(?!/api/).*$" description="Expression that will match paths for the resources on the web server that should redirect to the LoginPage when authentication fails." encrypted="false"/>
<add name="AnonymousResourceExpression" value="^/@|^/Scripts/|^/Content/|^/Images/|^/fonts/|^/favicon.ico$|^/api/grafana(/|$)" description="Expression that will match paths for the resources on the web server that can be provided without checking credentials." encrypted="false"/>
<add name="AnonymousResourceExpression" value="^/@|^/Scripts/|^/Content/|^/Images/|^/fonts/|^/favicon.ico$|^/api/grafana(/|$)|^/swagger" description="Expression that will match paths for the resources on the web server that can be provided without checking credentials." encrypted="false"/>
<add name="AuthenticationToken" value="x-gsf-auth" description="Defines the token used for identifying the authentication token in cookie headers." encrypted="false"/>
<add name="SessionToken" value="x-gsf-session" description="Defines the token used for identifying the session ID in cookie headers." encrypted="false"/>
<add name="RequestVerificationToken" value="X-GSF-Verify" description="Defines the token used for anti-forgery verification in HTTP request headers." encrypted="false"/>
Expand Down
2 changes: 1 addition & 1 deletion Source/Applications/openPDC/openPDC/AppDebug.config
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
<add name="BootstrapTheme" value="Content/bootstrap-theme.min.css" description="Path to Bootstrap CSS to use for rendering styles." encrypted="false" />
<add name="AuthenticationSchemes" value="Ntlm, Basic" description="Comma separated list of authentication schemes to use for clients accessing the hosted web server, e.g., Basic or NTLM." encrypted="false" />
<add name="AuthFailureRedirectResourceExpression" value="^/$|^/.+\.cshtml$|^/.+\.vbhtml$|^/grafana(?!/api/)" description="Expression that will match paths for the resources on the web server that should redirect to the LoginPage when authentication fails." encrypted="false" />
<add name="AnonymousResourceExpression" value="^/@|^/Scripts/|^/Content/|^/Images/|^/fonts/|^/favicon.ico$|^/api/grafana(/|$)" description="Expression that will match paths for the resources on the web server that can be provided without checking credentials." encrypted="false" />
<add name="AnonymousResourceExpression" value="^/@|^/Scripts/|^/Content/|^/Images/|^/fonts/|^/favicon.ico$|^/api/grafana(/|$)|^/swagger" description="Expression that will match paths for the resources on the web server that can be provided without checking credentials." encrypted="false" />
<add name="AuthenticationToken" value="x-gsf-auth" description="Defines the token used for identifying the authentication token in cookie headers." encrypted="false" />
<add name="SessionToken" value="x-gsf-session" description="Defines the token used for identifying the session ID in cookie headers." encrypted="false" />
<add name="LoginPage" value="/@GSF/Web/Security/Views/Login.cshtml" description="Defines the login page used for redirects on authentication failure. Expects forward slash prefix." encrypted="false" />
Expand Down
80 changes: 57 additions & 23 deletions Source/Applications/openPDC/openPDC/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,6 @@
//
//******************************************************************************************************

using System;
using System.Security;
using System.Web.Http;
using System.Web.Http.Cors;
using System.Web.Http.ExceptionHandling;
using GSF.IO;
using GSF.Web;
using GSF.Web.Hosting;
Expand All @@ -36,9 +31,16 @@
using ModbusAdapters;
using Newtonsoft.Json;
using openPDC.Adapters;
using Owin;
using openPDC.Model;
using Owin;
using PhasorWebUI;
using Swashbuckle.Application;
using System;
using System.IO;
using System.Security;
using System.Web.Http;
using System.Web.Http.Cors;
using System.Web.Http.ExceptionHandling;

namespace openPDC
{
Expand All @@ -53,6 +55,11 @@ public override void Handle(ExceptionHandlerContext context)

public class Startup
{
/// <summary>
/// Gets the authentication options used for the hosted web server.
/// </summary>
public static AuthenticationOptions AuthenticationOptions { get; } = new AuthenticationOptions();

public void Configuration(IAppBuilder app)
{
// Add Content-Security Headers
Expand All @@ -62,7 +69,9 @@ public void Configuration(IAppBuilder app)
{
await next();

if (!context.Response.Headers.ContainsKey("Content-Security-Policy"))
bool isSwaggerPath = context.Request.Path.Value?.StartsWith("/swagger", StringComparison.OrdinalIgnoreCase) == true;

if (!isSwaggerPath && !context.Response.Headers.ContainsKey("Content-Security-Policy"))
context.Response.Headers.Add("Content-Security-Policy", ["default-src: 'self'"]);

if (context.Request.Scheme == "https" && !context.Response.Headers.ContainsKey("Strict-Transport-Security"))
Expand All @@ -77,15 +86,16 @@ public void Configuration(IAppBuilder app)
}
});

// Modify the JSON serializer to serialize dates as UTC - otherwise, timezone will not be appended
// to date strings and browsers will select whatever timezone suits them
// Modify the JSON serializer to serialize dates as UTC - otherwise, timezone will not
// be appended to date strings and browsers will select whatever timezone suits them
JsonSerializerSettings settings = JsonUtility.CreateDefaultSerializerSettings();
settings.DateTimeZoneHandling = DateTimeZoneHandling.Utc;
JsonSerializer serializer = JsonSerializer.Create(settings);
GlobalHost.DependencyResolver.Register(typeof(JsonSerializer), () => serializer);
AppModel model = Program.Host.Model;

// Load security hub into application domain before establishing SignalR hub configuration, initializing default status and exception handlers
// Load security hub into application domain before establishing SignalR hub
// configuration, initializing default status and exception handlers
try
{
using (new SecurityHub(
Expand Down Expand Up @@ -119,7 +129,7 @@ public void Configuration(IAppBuilder app)
Program.Host.LogException
))
{
WebExtensions.AddEmbeddedResourceAssembly(hub.GetType().Assembly);
WebExtensions.AddEmbeddedResourceAssembly(hub.GetType().Assembly);
}
}
catch (Exception ex)
Expand All @@ -145,9 +155,8 @@ public void Configuration(IAppBuilder app)
// Enable GSF role-based security authentication
app.UseAuthentication(AuthenticationOptions);

// Enable cross-domain scripting default policy - controllers can manually
// apply "EnableCors" attribute to class or an action to override default
// policy configured here
// Enable cross-domain scripting default policy - controllers can manually apply
// "EnableCors" attribute to class or an action to override default policy configured here
try
{
if (!string.IsNullOrWhiteSpace(model.Global.DefaultCorsOrigins))
Expand Down Expand Up @@ -180,6 +189,12 @@ public void Configuration(IAppBuilder app)
{
using (new GrafanaController()) { }

using (new DeviceController()) { }

using (new PhasorController()) { }

using (new DevicePhasorController()) { }

httpConfig.Routes.MapHttpRoute(
name: "CustomAPIs",
routeTemplate: "api/{controller}/{action}/{id}",
Expand All @@ -194,6 +209,30 @@ public void Configuration(IAppBuilder app)
// Set configuration to use reflection to setup routes
httpConfig.MapHttpAttributeRoutes();

// Configure Swagger UI for custom API documentation
try
{
httpConfig.EnableSwagger(c =>
{
c.SingleApiVersion("v1", "openPDC Custom APIs")
.Description("REST API endpoints for device management and phasor data in openPDC.");

string baseDir = AppDomain.CurrentDomain.BaseDirectory;

string openPDCXml = Path.Combine(baseDir, "openPDC.xml");
if (File.Exists(openPDCXml))
c.IncludeXmlComments(openPDCXml);

string adaptersXml = Path.Combine(baseDir, "openPDC.Adapters.xml");
if (File.Exists(adaptersXml))
c.IncludeXmlComments(adaptersXml);
}).EnableSwaggerUi();
}
catch (Exception ex)
{
Program.Host.LogException(new InvalidOperationException($"Failed to initialize Swagger: {ex.Message}", ex));
}

// Load the WebPageController class and assign its routes
app.UseWebApi(httpConfig);

Expand All @@ -208,8 +247,8 @@ private void Load_ModbusAssembly()
{
try
{
// Wrap class reference in lambda function to force
// assembly load errors to occur within the try-catch
// Wrap class reference in lambda function to force assembly load errors to occur
// within the try-catch
new Action(() =>
{
// Make embedded resources of Modbus poller available to web server
Expand All @@ -224,12 +263,7 @@ private void Load_ModbusAssembly()
Program.Host.LogException(new InvalidOperationException($"Failed to load Modbus assembly: {ex.Message}", ex));
}
}

// Static Properties

/// <summary>
/// Gets the authentication options used for the hosted web server.
/// </summary>
public static AuthenticationOptions AuthenticationOptions { get; } = new AuthenticationOptions();
// Static Properties
}
}
}
6 changes: 6 additions & 0 deletions Source/Applications/openPDC/openPDC/openPDC.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
<OutputPath>..\..\..\..\Build\Output\Debug\Applications\openPDC\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<DocumentationFile>..\..\..\..\Build\Output\Debug\Applications\openPDC\openPDC.xml</DocumentationFile>
<WarningLevel>4</WarningLevel>
<UseVSHostingProcess>false</UseVSHostingProcess>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
Expand All @@ -73,6 +74,7 @@
<WarningLevel>4</WarningLevel>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>false</Prefer32Bit>
<DocumentationFile>..\..\..\..\Build\Output\Release\Applications\openPDC\openPDC.xml</DocumentationFile>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
<DebugSymbols>true</DebugSymbols>
Expand Down Expand Up @@ -118,6 +120,10 @@
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Reference Include="Swashbuckle.Core">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\Dependencies\GSF\Swashbuckle.Core.dll</HintPath>
</Reference>
<Reference Include="AjaxMin, Version=5.14.5506.26196, Culture=neutral, PublicKeyToken=21ef50ce11b5d80f, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\Dependencies\GSF\AjaxMin.dll</HintPath>
Expand Down
5 changes: 5 additions & 0 deletions Source/Applications/openPDC/openPDCSetup/openPDCSetup.wxs
Original file line number Diff line number Diff line change
Expand Up @@ -1131,6 +1131,11 @@
<netfx:NativeImage Id="ngen_System.Web.Http.Cors.dll" Platform="64bit" Priority="0" AppBaseDirectory="INSTALLFOLDER"/>
</File>
</Component>
<Component Id="Swashbuckle.Core">
<File Id="Swashbuckle.Core.dll" Name="Swashbuckle.Core.dll" Source="$(var.SolutionDir)\Dependencies\GSF\Swashbuckle.Core.dll">
<netfx:NativeImage Id="ngen_Swashbuckle.Core.dll" Platform="64bit" Priority="0" AppBaseDirectory="INSTALLFOLDER"/>
</File>
</Component>
<Component Id="Microsoft.Owin">
<File Id="Microsoft.Owin.dll" Name="Microsoft.Owin.dll" Source="$(var.SolutionDir)\Dependencies\GSF\Microsoft.Owin.dll">
<netfx:NativeImage Id="ngen_Microsoft.Owin.dll" Platform="64bit" Priority="0" AppBaseDirectory="INSTALLFOLDER"/>
Expand Down
Binary file added Source/Dependencies/GSF/Swashbuckle.Core.dll
Binary file not shown.
14 changes: 14 additions & 0 deletions Source/Libraries/openPDC.Adapters/Constants/StringConstant.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
namespace openPDC.Adapters.Constants
{
internal static class StringConstant
{
#region [ Constants ]

internal const string Acronym = "Acronym";
internal const string DeviceID = "DeviceID";
internal const string SourceIndex = "SourceIndex";
internal const string SystemSettings = "systemSettings";

#endregion [ Constants ]
}
}
Loading