Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Connecting to server with spaces in URL #82

Open
Syphontwo opened this issue Jun 1, 2018 · 8 comments
Open

Connecting to server with spaces in URL #82

Syphontwo opened this issue Jun 1, 2018 · 8 comments

Comments

@Syphontwo
Copy link

Syphontwo commented Jun 1, 2018

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.

@Nubber99
Copy link

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.

@Nubber99
Copy link

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

@Syphontwo
Copy link
Author

Syphontwo commented Jan 23, 2020

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);
     }

@Syphontwo
Copy link
Author

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...

@Nubber99
Copy link

Nubber99 commented Jan 23, 2020

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.
image

@Syphontwo
Copy link
Author

Syphontwo commented Jan 23, 2020

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;
        }

@Syphontwo
Copy link
Author

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.

@Nubber99
Copy link

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants