h-opc
h-opc copied to clipboard
Connecting to server with spaces in URL
I see on the version posted here is GitHub, there is a comment in h-opc/h-opc/Da/DaClient.cs which states
/// <param name="serverUrl">The url of the server to connect to. WARNING: If server URL includes
/// spaces (ex. "RSLinx OPC Server") then pass the server URL in to the constructor as an Opc.URL object
/// directly instead.</param>
However the constructor:
public DaClient(URL serverUrl)
{
_url = serverUrl;
}
Is not available when using the package through visual studios NuGet Package Manager.
According to the NuGet package manager I have installed version 0.9.3 In this version, only the System.URI constructor is present. This is the latest version available via NuGet.
I was able to clone the repository, build it, and add it to a project. After this, I was able to build use it as expected. This issue appears to be related to the latest NuGet version not matching the source here on GitHub.
I think that this is still a problem. Could you post a bit of code to show how you got around this? I'm using the latest binaries, and they still throw an exception when there's a space in the name.
In fact, the following piece of code does work and it's using the same OPC Foundation DLL's. The OPC Server does have spaces in it's name. So i's not the OPC Foundatrion DLL's. I'm connecting to a DA server, bye the way.
Public Sub MyOPC() Dim url As Opc.URL = New Opc.URL("opcda://localhost/National Instruments.Variable Engine.1") Dim server As Opc.Da.Server = Nothing Dim fact As OpcCom.Factory = New OpcCom.Factory server = New Opc.Da.Server(fact, Nothing) server.Connect(url, New Opc.ConnectData(New System.Net.NetworkCredential))
Dim sstate As Opc.Da.ServerStatus
sstate = server.GetStatus()
If sstate.ServerState <> Opc.Da.serverState.running Then
Console.Write("Server not running")
Application.Exit()
End If
Unfortunately, I do not have that working code on hand. I'll have to do a lot of digging to find it. I was able to locate another useful snippit though, this is an overload for the Connect
method in Da/DaClinet.cs
I will continue to try and find the connection method I changed to allow spaces in the URL, but no promises. I have since left the role where I did this work and most of the code stayed with my previous employer (except some of the open source work I did, which this may have been in that folder).
/// Connect using username and password credentials
/// </summary>
/// <param name="userName">the username to use with NetworkCredentials</param>
/// <param name="password">the password to use with NetworkCredentials</param>
public void Connect(string userName, string password)
{
if (Status == OpcStatus.Connected)
return;
_server = new OpcDa.Server(new Factory(), _url);
_server.Connect(new ConnectData(new System.Net.NetworkCredential(userName, password)));
var root = new DaNode(string.Empty, string.Empty);
RootNode = root;
AddNodeToCache(root);
}
Now I remember...
It isn't a code change that fixed it. I had to bring the project down from github, then manually rebuild it as part of a larger project. This forced it to grab a newer version of the NuGet repositories which allowed it to run with the space character in URLs. All the code I wrote was to add functionality that I required for my specific project, such as username and password login.
Sorry I can't offer much more help than that. Try grabbing the repository and building it yourself, bringing the NuGet packages to their latest versions. That worked over a year ago, so things might be different now...
Thanks for the reply. I tried what you suggested, but it still doesn't work. The URL has a %20 in it (for the space) and it looks like OpcNetApi.dll doesn't know what to do with that. Looks like I'll have to try another solution.
I found some snippits of old code that may or may not be helpful.
Looks like I stored their info as a URI in my own Server
objects
/// <summary>
/// Full URI to access server using Hylasoft.Opc
/// </summary>
[XmlElement("URI")]
public string Uri { get; set; }
I had some prep work before connecting
/// <summary>
/// Get a new client ready to connect, but do not actually connect it
/// </summary>
/// <returns>new, prepared client</returns>
private DaClient PrepClient()
{
var info = ConnectionInformation.Servers.Instance.ServersList.PLCServers.FirstOrDefault((e) => e.Name == this.Name);
return new DaClient(
new Opc.URL(info.Uri + "/" + info.Pid)
);
}
I then had a whole series of functions to check for connection errors and such, but here is the method I used to connect. NOTE: this uses the username and password credential functionality that I added in a fork to the DaClient. Check my public repositories if you are interested in that.
private DaClient client;
/// <summary>
/// Attempt to connect to the prepared client. Increment a counter on any failure, then rethrow internal error
/// </summary>
/// <returns>connection status after attempt to connect</returns>
public ConnectionStatus Connect()
{
var credentials = ConnectionInformation.Servers.Instance.ServersList.PLCServers
.FirstOrDefault((e) => e.Name == this.Name).Credentials;
try //try to connect
{
this.client.Connect(credentials.Username, credentials.Password);
}
catch (Exception) //on Any failure, increment failed connection count and rethrow to caller
{
this.FailedConnectionAttempts += 1;
if (this.FailedConnectionAttempts >= int.MaxValue - 1) //just to prevent overflow
{
this.FailedConnectionAttempts = 0;
}
//Add error logging here for connection debugging
throw;
}
return this.Status;
}
Just adding another post to re-iterate what I -believe- was the most important bit of info.
Store the URL as a URI object. Then, when creating a new DaClient
pass the URI as a new Opc.URL
using new Opc.URL(URI uri)
. I believe the automatic URI to string conversion that occurs when you call that constructor should allow you to get around space issue.
This is my best guess at the black magic I performed a few years ago. Like I said, this is old stuff that I only have bits and pieces of laying around.
You cracked it!
Here's what I did: (VB)
Dim myurl As New Uri("opcda://localhost/National Instruments.Variable Engine.1") myclient = New Hylasoft.Opc.Da.DaClient(New Opc.URL(myurl.ToString)) or, in a shorter fashion: myclient = New Hylasoft.Opc.Da.DaClient(New Opc.URL("opcda://localhost/National Instruments.Variable Engine.1")) And it works!
Many thanks. This should be in the documentation.