ArcSDE connection timeout .NET

2721
9
03-30-2014 02:57 PM
JonathanBailey
Occasional Contributor III
If an invalid value for a connection string is passed to SDEWorkspaceFactory.OpenFromString(), the call hangs:

IWorkspaceFactory workspaceFactory = _workspaceFactory.OpenFromString("InvalidConnectionString", 0);


If I break execution, I can see from the call stack that control is still with the unmanaged code. Unfortunately, this OpenFromString doesn't offer a timeout. What I need to do is, within my .NET managed code, cancel the call to OpenFromString after a certain timeout period. I've tried a couple of approaches, including the following:

Task<IWorkspace> task = new Task<IWorkspace>(() => 
    { 
        return _workspaceFactory.OpenFromString("InvalidConnectionString", 0); 
    });
if (!task.Wait(10000))
{
    throw new TimeoutException();
}
IWorkspace workspace = task.Result;


In this case, task.Wait() always returns false, and task.Result() is always null, even if a valid value for the connection string is passed.

I've also tried the following approach:

IWorkspace workspace = null;
Thread thread = new Thread(() =>
    {
        workspace = _workspaceFactory.OpenFromString("InvalidConnectionString", 0);
    });
thread.Start();
if (!thread.Join(10000))
{
    throw new TimeoutException();
}


In this case, if a valid value for the connection string is passed, execution works as expected, but if an invalid value is passed, the execution still hangs in the unmanaged code, and thread.Join() never returns.

Any suggestions on how to do this?
0 Kudos
9 Replies
KevinYanuk
Occasional Contributor
If an invalid value for a connection string is passed to SDEWorkspaceFactory.OpenFromString(), the call hangs:

IWorkspaceFactory workspaceFactory = _workspaceFactory.OpenFromString("InvalidConnectionString", 0);


If I break execution, I can see from the call stack that control is still with the unmanaged code. Unfortunately, this OpenFromString doesn't offer a timeout. What I need to do is, within my .NET managed code, cancel the call to OpenFromString after a certain timeout period. I've tried a couple of approaches, including the following:

Task<IWorkspace> task = new Task<IWorkspace>(() => 
    { 
        return _workspaceFactory.OpenFromString("InvalidConnectionString", 0); 
    });
if (!task.Wait(10000))
{
    throw new TimeoutException();
}
IWorkspace workspace = task.Result;


In this case, task.Wait() always returns false, and task.Result() is always null, even if a valid value for the connection string is passed.

I've also tried the following approach:

IWorkspace workspace = null;
Thread thread = new Thread(() =>
    {
        workspace = _workspaceFactory.OpenFromString("InvalidConnectionString", 0);
    });
thread.Start();
if (!thread.Join(10000))
{
    throw new TimeoutException();
}


In this case, if a valid value for the connection string is passed, execution works as expected, but if an invalid value is passed, the execution still hangs in the unmanaged code, and thread.Join() never returns.

Any suggestions on how to do this?




Does it hang indefinitely?  The way I usually handle timeouts / invalid connection strings is to put the connection logic into a try block, which eventually should be caught:

          IWorkspace _workspace;

           try
            {
                 var factoryType = Type.GetTypeFromProgID("esriDataSourcesGDB.SdeWorkspaceFactory");
                 var workspaceFactory = (IWorkspaceFactory)Activator.CreateInstance(factoryType);
                 _workspace = workspaceFactory.OpenFromFile(this.Path, 0);

                 Marshal.ReleaseComObject(workspaceFactory);
            }
            catch
            {
                throw new BadDatabaseConnectionException("Unable to connect to database");
            }



Also, (I dont have a lot of experience with the Thread in .NET), be careful multithreading with ArcObjects... if you create or access your workspace (or any ArcObject) from one thread, and try to use it on another, you will see some problems (STA).
0 Kudos
JonathanBailey
Occasional Contributor III
Yes, it hangs indefinitely.
0 Kudos
JonathanBailey
Occasional Contributor III
Yes, it hangs indefinitely.
0 Kudos
KevinYanuk
Occasional Contributor
Yes, it hangs indefinitely.


I would try to see if you get the same result from a single thread, and putting your code in a try catch block to see if you can catch any kind of exception thrown by the invalid connection string.
0 Kudos
JonathanBailey
Occasional Contributor III
There's no exception thrown.

If the SDEWorkspaceFactory receives an invalid connection string or incomplete connection parameters, it opens up a dialog prompting the user for additional connection parameters. This seems to be a poor design, as it assumes that it will be used in an application in which there will be user interaction. In some cases, there is no interaction, and really an exception should be thrown if there are incomplete connection parameters.
0 Kudos
KevinYanuk
Occasional Contributor
There's no exception thrown.

If the SDEWorkspaceFactory receives an invalid connection string or incomplete connection parameters, it opens up a dialog prompting the user for additional connection parameters. This seems to be a poor design, as it assumes that it will be used in an application in which there will be user interaction. In some cases, there is no interaction, and really an exception should be thrown if there are incomplete connection parameters.



I've received a dialog box when opening SDE connections only when the authentication type is user/pass and not OSA, or if the user credentials are not passed into the workspace through a property set:

    IPropertySet propertySet = new PropertySetClass();
    propertySet.SetProperty("SERVER", server);
    propertySet.SetProperty("INSTANCE", instance);
    propertySet.SetProperty("DATABASE", database);
    propertySet.SetProperty("USER", user);
    propertySet.SetProperty("PASSWORD", password);
    propertySet.SetProperty("VERSION", version);

    Type factoryType = Type.GetTypeFromProgID("esriDataSourcesGDB.SdeWorkspaceFactory");
    IWorkspaceFactory workspaceFactory = (IWorkspaceFactory)Activator.CreateInstance(factoryType);
    workspaceFactory.Open(propertySet, 0);


Not sure how your connection string is formatted.
0 Kudos
JonathanBailey
Occasional Contributor III
I can't guarantee that the connection method will be OSA; it might be database. I'm relying on clients of my code to provide a valid connection string, so it might be a passage from Finnegans Wake for all I know.

I could write a bunch of code to validate the connection string passed, but my thinking is that this is something that Esri should be checking and returning an error for. Since it doesn't seem that Esri does this, I was hoping to find a way to timeout and throw an exception, rather than having to write and maintain a whole bunch of string validation code.
0 Kudos
KevinYanuk
Occasional Contributor
I can't guarantee that the connection method will be OSA; it might be database. I'm relying on clients of my code to provide a valid connection string, so it might be a passage from Finnegans Wake for all I know.

I could write a bunch of code to validate the connection string passed, but my thinking is that this is something that Esri should be checking and returning an error for. Since it doesn't seem that Esri does this, I was hoping to find a way to timeout and throw an exception, rather than having to write and maintain a whole bunch of string validation code.



Yeah... such is often the case with ArcObjects... sorry I can't be of more help.  I'll often find writing my own solution for these things work out better in the end, anyway.  I'm still struggling to get a Java ArcMap addin to even show up in the commands window after its been installed!
0 Kudos
JonathanBailey
Occasional Contributor III
I can't guarantee that the connection method will be OSA; it might be database. I'm relying on clients of my code to provide a valid connection string, so there's a chance that it might be gibberish. I could write a bunch of code to validate the connection string passed, but my thinking is that this is something that Esri should be checking and returning an error for.
0 Kudos