示例#1
0
        public async Task OneTimeSetUpAsync()
        {
            // this test fails on macOS, ignore (TODO)
            if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
            {
                Assert.Ignore("Reverse connect fails on mac OS.");
            }

            // pki directory root for test runs.
            PkiRoot = Path.GetTempPath() + Path.GetRandomFileName();

            // start ref server with reverse connect
            ServerFixture = new ServerFixture <ReferenceServer> {
                AutoAccept            = true,
                SecurityNone          = true,
                ReverseConnectTimeout = MaxTimeout,
                TraceMasks            = Utils.TraceMasks.Error | Utils.TraceMasks.Security
            };
            ReferenceServer = await ServerFixture.StartAsync(TestContext.Out, PkiRoot).ConfigureAwait(false);

            // create client
            ClientFixture = new ClientFixture();
            await ClientFixture.LoadClientConfiguration(PkiRoot).ConfigureAwait(false);

            await ClientFixture.StartReverseConnectHost().ConfigureAwait(false);

            m_endpointUrl = new Uri(Utils.ReplaceLocalhost("opc.tcp://localhost:" + ServerFixture.Port.ToString()));
            // start reverse connection
            ReferenceServer.AddReverseConnection(new Uri(ClientFixture.ReverseConnectUri), MaxTimeout);
        }
示例#2
0
        public async Task ConnectJWT(string securityPolicy)
        {
            var identityToken = "fakeTokenString";

            var issuedToken = new IssuedIdentityToken()
            {
                IssuedTokenType    = IssuedTokenType.JWT,
                PolicyId           = Profiles.JwtUserToken,
                DecryptedTokenData = Encoding.UTF8.GetBytes(identityToken)
            };

            var userIdentity = new UserIdentity(issuedToken);

            var session = await ClientFixture.ConnectAsync(ServerUrl, securityPolicy, Endpoints, userIdentity).ConfigureAwait(false);

            Assert.NotNull(session);
            Assert.NotNull(TokenValidator.LastIssuedToken);

            var receivedToken = Encoding.UTF8.GetString(TokenValidator.LastIssuedToken.DecryptedTokenData);

            Assert.AreEqual(identityToken, receivedToken);

            var result = session.Close();

            Assert.NotNull(result);

            session.Dispose();
        }
        public async Task OneTimeSetUpAsync()
        {
            // this test fails on macOS, ignore
            if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
            {
                Assert.Ignore("Reverse connect fails on mac OS.");
            }

            // start ref server
            m_serverFixture = new ServerFixture <ReferenceServer> {
                AutoAccept            = true,
                SecurityNone          = true,
                ReverseConnectTimeout = MaxTimeout,
                TraceMasks            = Utils.TraceMasks.Error | Utils.TraceMasks.Security
            };
            m_server = await m_serverFixture.StartAsync(TestContext.Out).ConfigureAwait(false);

            // create client
            m_clientFixture = new ClientFixture();
            await m_clientFixture.LoadClientConfiguration().ConfigureAwait(false);

            await m_clientFixture.StartReverseConnectHost().ConfigureAwait(false);

            m_endpointUrl = new Uri(Utils.ReplaceLocalhost("opc.tcp://localhost:" + m_serverFixture.Port.ToString()));
            // start reverse connection
            m_server.AddReverseConnection(new Uri(m_clientFixture.ReverseConnectUri), MaxTimeout);
        }
示例#4
0
        public async Task ConnectMultipleSessionsAsync()
        {
            var endpoint = await ClientFixture.GetEndpointAsync(this.ServerUrl, SecurityPolicies.Basic256Sha256, this.Endpoints);

            Assert.NotNull(endpoint);

            var channel = await ClientFixture.CreateChannelAsync(endpoint).ConfigureAwait(false);

            Assert.NotNull(channel);

            var session1 = ClientFixture.CreateSession(channel, endpoint);

            session1.Open("Session1", null);

            var session2 = ClientFixture.CreateSession(channel, endpoint);

            session2.Open("Session2", null);

            session1.Close(closeChannel: false);
            session1.DetachChannel();
            session1.Dispose();

            _ = session2.ReadValue(VariableIds.Server_ServerStatus, typeof(ServerStatusDataType));

            session2.Close(closeChannel: false);
            session2.DetachChannel();
            session2.Dispose();

            channel.Dispose();
        }
示例#5
0
        public async Task ConnectAndReconnectAsync()
        {
            const int connectTimeout = MaxTimeout;
            var       session        = await ClientFixture.ConnectAsync(ServerUrl, SecurityPolicies.Basic256Sha256, Endpoints).ConfigureAwait(false);

            Assert.NotNull(session);

            ManualResetEvent quitEvent = new ManualResetEvent(false);
            var reconnectHandler       = new SessionReconnectHandler();

            reconnectHandler.BeginReconnect(session, connectTimeout / 5,
                                            (object sender, EventArgs e) => {
                // ignore callbacks from discarded objects.
                if (!Object.ReferenceEquals(sender, reconnectHandler))
                {
                    return;
                }

                session = reconnectHandler.Session;
                reconnectHandler.Dispose();
                quitEvent.Set();
            });

            var timeout = quitEvent.WaitOne(connectTimeout);

            Assert.True(timeout);

            var result = session.Close();

            Assert.NotNull(result);
            session.Dispose();
        }
示例#6
0
        public async Task BrowseFullAddressSpace(string securityPolicy)
        {
            if (OperationLimits == null)
            {
                GetOperationLimits();
            }

            var requestHeader = new RequestHeader();

            requestHeader.Timestamp   = DateTime.UtcNow;
            requestHeader.TimeoutHint = MaxTimeout;

            // Session
            Session session;

            if (securityPolicy != null)
            {
                session = await ClientFixture.ConnectAsync(ServerUrl, securityPolicy, Endpoints).ConfigureAwait(false);
            }
            else
            {
                session = Session;
            }

            var clientTestServices = new ClientTestServices(session);

            ReferenceDescriptions = CommonTestWorkers.BrowseFullAddressSpaceWorker(clientTestServices, requestHeader, OperationLimits);

            if (securityPolicy != null)
            {
                session.Close();
                session.Dispose();
            }
        }
示例#7
0
        /// <summary>
        /// Setup a server and client fixture.
        /// </summary>
        /// <param name="writer">The test output writer.</param>
        public async Task OneTimeSetUpAsync(TextWriter writer = null)
        {
            // start Ref server
            m_serverFixture = new ServerFixture <ReferenceServer> {
                UriScheme       = m_uriScheme,
                SecurityNone    = true,
                AutoAccept      = true,
                OperationLimits = true
            };
            if (writer != null)
            {
                m_serverFixture.TraceMasks = Utils.TraceMasks.Error;
            }
            m_server = await m_serverFixture.StartAsync(writer ?? TestContext.Out).ConfigureAwait(false);

            m_clientFixture = new ClientFixture();
            await m_clientFixture.LoadClientConfiguration().ConfigureAwait(false);

            m_clientFixture.Config.TransportQuotas.MaxMessageSize    =
                m_clientFixture.Config.TransportQuotas.MaxBufferSize = 4 * 1024 * 1024;
            m_url = new Uri(m_uriScheme + "://localhost:" + m_serverFixture.Port.ToString());
            try
            {
                m_session = await m_clientFixture.ConnectAsync(m_url, SecurityPolicies.Basic256Sha256).ConfigureAwait(false);
            }
            catch (Exception e)
            {
                Assert.Ignore("OneTimeSetup failed to create session, tests skipped. Error: {0}", e.Message);
            }
        }
 /// <summary>
 /// Global Setup for benchmarks.
 /// </summary>
 public void GlobalSetup()
 {
     Console.WriteLine("GlobalSetup: Start Server");
     OneTimeSetUpAsync(Console.Out).GetAwaiter().GetResult();
     Console.WriteLine("GlobalSetup: Connecting");
     Session = ClientFixture.ConnectAsync(ServerUrl, SecurityPolicy).GetAwaiter().GetResult();
     Console.WriteLine("GlobalSetup: Ready");
 }
示例#9
0
        public async Task Connect(string securityPolicy)
        {
            var session = await ClientFixture.ConnectAsync(ServerUrl, securityPolicy, Endpoints).ConfigureAwait(false);

            Assert.NotNull(session);
            var result = session.Close();

            Assert.NotNull(result);
            session.Dispose();
        }
示例#10
0
        public async Task ReverseConnect(string securityPolicy)
        {
            // ensure endpoints are available
            await RequireEndpoints().ConfigureAwait(false);

            // get a connection
            var config = ClientFixture.Config;
            ITransportWaitingConnection connection;

            using (var cancellationTokenSource = new CancellationTokenSource(MaxTimeout))
            {
                connection = await ClientFixture.ReverseConnectManager.WaitForConnection(
                    m_endpointUrl, null, cancellationTokenSource.Token).ConfigureAwait(false);

                Assert.NotNull(connection, "Failed to get connection.");
            }

            // select the secure endpoint
            var endpointConfiguration = EndpointConfiguration.Create(config);
            var selectedEndpoint      = ClientFixture.SelectEndpoint(config, Endpoints, m_endpointUrl, securityPolicy);

            Assert.NotNull(selectedEndpoint);
            var endpoint = new ConfiguredEndpoint(null, selectedEndpoint, endpointConfiguration);

            Assert.NotNull(endpoint);

            // connect
            var session = await Session.Create(config, connection, endpoint, false, false, "Reverse Connect Client",
                                               MaxTimeout, new UserIdentity(new AnonymousIdentityToken()), null).ConfigureAwait(false);

            Assert.NotNull(session);

            // default request header
            var requestHeader = new RequestHeader();

            requestHeader.Timestamp   = DateTime.UtcNow;
            requestHeader.TimeoutHint = MaxTimeout;

            // Browse
            var clientTestServices    = new ClientTestServices(session);
            var referenceDescriptions = CommonTestWorkers.BrowseFullAddressSpaceWorker(clientTestServices, requestHeader);

            Assert.NotNull(referenceDescriptions);

            // close session
            var result = session.Close();

            Assert.NotNull(result);
            session.Dispose();
        }
示例#11
0
        public async Task TransferSubscriptionNative(bool sendInitialData)
        {
            Session transferSession = null;

            try
            {
                var requestHeader = new RequestHeader {
                    Timestamp   = DateTime.UtcNow,
                    TimeoutHint = MaxTimeout
                };

                // to validate the behavior of the sendInitialValue flag,
                // use a static variable to avoid sampled notifications in publish requests
                var      namespaceUris      = Session.NamespaceUris;
                NodeId[] testSet            = CommonTestWorkers.NodeIdTestSetStatic.Select(n => ExpandedNodeId.ToNodeId(n, namespaceUris)).ToArray();
                var      clientTestServices = new ClientTestServices(Session);
                var      subscriptionIds    = CommonTestWorkers.CreateSubscriptionForTransfer(clientTestServices, requestHeader, testSet, 0, -1);

                TestContext.Out.WriteLine("Transfer SubscriptionIds: {0}", subscriptionIds[0]);

                transferSession = await ClientFixture.ConnectAsync(ServerUrl, SecurityPolicies.Basic256Sha256, Endpoints).ConfigureAwait(false);

                Assert.AreNotEqual(Session.SessionId, transferSession.SessionId);

                requestHeader = new RequestHeader {
                    Timestamp   = DateTime.UtcNow,
                    TimeoutHint = MaxTimeout
                };
                var transferTestServices = new ClientTestServices(transferSession);
                CommonTestWorkers.TransferSubscriptionTest(transferTestServices, requestHeader, subscriptionIds, sendInitialData, false);

                // verify the notification of message transfer
                requestHeader = new RequestHeader {
                    Timestamp   = DateTime.UtcNow,
                    TimeoutHint = MaxTimeout
                };
                CommonTestWorkers.VerifySubscriptionTransferred(clientTestServices, requestHeader, subscriptionIds, true);

                transferSession.Close();
            }
            finally
            {
                transferSession?.Dispose();
            }
        }
        /// <summary>
        /// Setup a server and client fixture.
        /// </summary>
        /// <param name="writer">The test output writer.</param>
        public async Task OneTimeSetUpAsync(TextWriter writer = null)
        {
            // start Ref server
            m_serverFixture                 = new ServerFixture <ReferenceServer>();
            m_clientFixture                 = new ClientFixture();
            m_serverFixture.AutoAccept      = true;
            m_serverFixture.OperationLimits = true;
            if (writer != null)
            {
                m_serverFixture.TraceMasks = Utils.TraceMasks.Error | Utils.TraceMasks.Security;
            }
            m_server = await m_serverFixture.StartAsync(writer ?? TestContext.Out).ConfigureAwait(false);

            await m_clientFixture.LoadClientConfiguration().ConfigureAwait(false);

            m_url     = new Uri("opc.tcp://localhost:" + m_serverFixture.Port.ToString());
            m_session = await m_clientFixture.ConnectAsync(m_url, SecurityPolicies.Basic256Sha256).ConfigureAwait(false);
        }
示例#13
0
        public async Task ReverseConnect2(bool updateBeforeConnect, bool checkDomain)
        {
            string securityPolicy = SecurityPolicies.Basic256Sha256;

            // ensure endpoints are available
            await RequireEndpoints().ConfigureAwait(false);

            // get a connection
            var config = ClientFixture.Config;

            // select the secure endpoint
            var endpointConfiguration = EndpointConfiguration.Create(config);
            var selectedEndpoint      = ClientFixture.SelectEndpoint(config, Endpoints, m_endpointUrl, securityPolicy);

            Assert.NotNull(selectedEndpoint);
            var endpoint = new ConfiguredEndpoint(null, selectedEndpoint, endpointConfiguration);

            Assert.NotNull(endpoint);

            // connect
            var session = await Session.Create(config, ClientFixture.ReverseConnectManager, endpoint, updateBeforeConnect, checkDomain, "Reverse Connect Client",
                                               MaxTimeout, new UserIdentity(new AnonymousIdentityToken()), null).ConfigureAwait(false);

            Assert.NotNull(session);

            // header
            var requestHeader = new RequestHeader();

            requestHeader.Timestamp   = DateTime.UtcNow;
            requestHeader.TimeoutHint = MaxTimeout;

            // Browse
            var clientTestServices    = new ClientTestServices(session);
            var referenceDescriptions = CommonTestWorkers.BrowseFullAddressSpaceWorker(clientTestServices, requestHeader);

            Assert.NotNull(referenceDescriptions);

            // close session
            var result = session.Close();

            Assert.NotNull(result);
            session.Dispose();
        }
 /// <summary>
 /// Test setup.
 /// </summary>
 public async Task SetUp()
 {
     if (!SingleSession)
     {
         try
         {
             Session = await ClientFixture.ConnectAsync(ServerUrl, SecurityPolicies.Basic256Sha256).ConfigureAwait(false);
         }
         catch (Exception e)
         {
             Assert.Ignore("OneTimeSetup failed to create session, tests skipped. Error: {0}", e.Message);
         }
     }
     if (ServerFixture == null)
     {
         ClientFixture.SetTraceOutput(TestContext.Out);
     }
     else
     {
         ServerFixture.SetTraceOutput(TestContext.Out);
     }
 }
        /// <summary>
        /// Setup a server and client fixture.
        /// </summary>
        /// <param name="writer">The test output writer.</param>
        public async Task OneTimeSetUpAsync(TextWriter writer = null)
        {
            // pki directory root for test runs.
            PkiRoot = Path.GetTempPath() + Path.GetRandomFileName();
            TestContext.Out.WriteLine("Using the Pki Root {0}", PkiRoot);

            // The parameters are read from the .runsettings file
            string customUrl = null;

            if (SupportsExternalServerUrl)
            {
                customUrl = TestContext.Parameters["ServerUrl"];
                if (customUrl?.StartsWith(UriScheme, StringComparison.Ordinal) == true)
                {
                    TestContext.Out.WriteLine("Using the external Server Url {0}", customUrl);

                    // load custom test sets
                    TestSetStatic     = ReadCustomTestSet("TestSetStatic");
                    TestSetSimulation = ReadCustomTestSet("TestSetSimulation");
                }
                else
                {
                    customUrl = null;
                }
            }

            if (customUrl == null)
            {
                // start Ref server
                ServerFixture = new ServerFixture <ReferenceServer> {
                    UriScheme       = UriScheme,
                    SecurityNone    = true,
                    AutoAccept      = true,
                    AllNodeManagers = true,
                    OperationLimits = true
                };

                if (writer != null)
                {
                    ServerFixture.TraceMasks = Utils.TraceMasks.Error | Utils.TraceMasks.Security;
                }

                await ServerFixture.LoadConfiguration(PkiRoot).ConfigureAwait(false);

                ServerFixture.Config.TransportQuotas.MaxMessageSize      =
                    ServerFixture.Config.TransportQuotas.MaxBufferSize   = TransportQuotaMaxMessageSize;
                ServerFixture.Config.TransportQuotas.MaxByteStringLength =
                    ServerFixture.Config.TransportQuotas.MaxStringLength = TransportQuotaMaxStringLength;
                ServerFixture.Config.ServerConfiguration.UserTokenPolicies.Add(
                    new UserTokenPolicy(UserTokenType.IssuedToken)
                {
                    IssuedTokenType = Opc.Ua.Profiles.JwtUserToken
                });

                ReferenceServer = await ServerFixture.StartAsync(writer ?? TestContext.Out).ConfigureAwait(false);

                ReferenceServer.TokenValidator = this.TokenValidator;
            }

            ClientFixture = new ClientFixture();
            await ClientFixture.LoadClientConfiguration(PkiRoot).ConfigureAwait(false);

            ClientFixture.Config.TransportQuotas.MaxMessageSize      =
                ClientFixture.Config.TransportQuotas.MaxBufferSize   = TransportQuotaMaxMessageSize;
            ClientFixture.Config.TransportQuotas.MaxByteStringLength =
                ClientFixture.Config.TransportQuotas.MaxStringLength = TransportQuotaMaxStringLength;

            if (!string.IsNullOrEmpty(customUrl))
            {
                ServerUrl = new Uri(customUrl);
            }
            else
            {
                ServerUrl = new Uri(UriScheme + "://localhost:" + ServerFixture.Port.ToString(CultureInfo.InvariantCulture));
            }

            if (SingleSession)
            {
                try
                {
                    Session = await ClientFixture.ConnectAsync(ServerUrl, SecurityPolicies.Basic256Sha256).ConfigureAwait(false);
                }
                catch (Exception e)
                {
                    Assert.Ignore("OneTimeSetup failed to create session, tests skipped. Error: {0}", e.Message);
                }
            }
        }
示例#16
0
        public async Task TransferSubscription(TransferType transferType, bool sendInitialValues)
        {
            const int kTestSubscriptions = 2;
            const int kDelay             = 2_000;

            // create test session and subscription
            var originSession = await ClientFixture.ConnectAsync(ServerUrl, SecurityPolicies.Basic256Sha256).ConfigureAwait(false);

            bool originSessionOpen = transferType == TransferType.KeepOpen;

            // create subscriptions
            var originSubscriptions        = new SubscriptionCollection();
            var originSubscriptionCounters = new int[kTestSubscriptions];
            var targetSubscriptionCounters = new int[kTestSubscriptions];

            for (int ii = 0; ii < kTestSubscriptions; ii++)
            {
                // create subscription with static monitored items
                var subscription = new Subscription(originSession.DefaultSubscription)
                {
                    PublishingInterval = 1_000,
                    PublishingEnabled  = true,
                };

                originSubscriptions.Add(subscription);
                originSession.AddSubscription(subscription);
                subscription.RepublishAfterTransfer = transferType == TransferType.DisconnectedRepublish;
                subscription.Create();

                // set defaults
                subscription.DefaultItem.DiscardOldest  = true;
                subscription.DefaultItem.QueueSize      = (ii == 0) ? 0U : 5;
                subscription.DefaultItem.MonitoringMode = MonitoringMode.Reporting;

                // create test set
                var namespaceUris = Session.NamespaceUris;
                var testSet       = new List <NodeId>();
                if (ii == 0)
                {
                    testSet.AddRange(GetTestSetStatic(namespaceUris));
                }
                else
                {
                    testSet.AddRange(GetTestSetSimulation(namespaceUris));
                }

                subscription.Handle = ii;
                var list = CreateMonitoredItemTestSet(subscription, testSet).ToList();
                list.ForEach(i => i.Notification += (MonitoredItem item, MonitoredItemNotificationEventArgs e) => {
                    originSubscriptionCounters[(int)subscription.Handle]++;
                    foreach (var value in item.DequeueValues())
                    {
                        TestContext.Out.WriteLine("Org:{0}: {1:20}, {2}, {3}, {4}", subscription.Id, item.DisplayName, value.Value, value.SourceTimestamp, value.StatusCode);
                    }
                });
                subscription.AddItems(list);
                subscription.ApplyChanges();
            }

            // settle
            await Task.Delay(kDelay).ConfigureAwait(false);

            // persist the subscription state
            var filePath = Path.GetTempFileName();

            // close session, do not delete subscription
            if (transferType != TransferType.KeepOpen)
            {
                originSession.DeleteSubscriptionsOnClose = false;
                originSession.Save(filePath);
                if (transferType == TransferType.CloseSession)
                {
                    // graceful close
                    originSession.Close();
                }
                else
                {
                    // force a socket dispose, to emulate network disconnect
                    // without closing session on server
                    originSession.TransportChannel.Dispose();
                }
            }

            // wait
            await Task.Delay(kDelay).ConfigureAwait(false);

            // close session, do not delete subscription
            if (transferType > TransferType.CloseSession)
            {
                originSession.Close();
            }

            // create target session
            var targetSession = await ClientFixture.ConnectAsync(ServerUrl, SecurityPolicies.Basic256Sha256).ConfigureAwait(false);

            // restore client state
            var transferSubscriptions = new SubscriptionCollection();

            if (transferType != TransferType.KeepOpen)
            {
                // load
                transferSubscriptions.AddRange(targetSession.Load(filePath));

                // hook notifications for log output
                int ii = 0;
                foreach (var subscription in transferSubscriptions)
                {
                    subscription.Handle = ii;
                    subscription.MonitoredItems.ToList().ForEach(i => i.Notification += (MonitoredItem item, MonitoredItemNotificationEventArgs e) => {
                        targetSubscriptionCounters[(int)subscription.Handle]++;
                        foreach (var value in item.DequeueValues())
                        {
                            TestContext.Out.WriteLine("Tra:{0}: {1:20}, {2}, {3}, {4}", subscription.Id, item.DisplayName, value.Value, value.SourceTimestamp, value.StatusCode);
                        }
                    });
                    ii++;
                }
            }
            else
            {
                transferSubscriptions.AddRange(originSubscriptions);
            }

            // wait
            await Task.Delay(kDelay).ConfigureAwait(false);

            // transfer restored subscriptions
            var result = targetSession.TransferSubscriptions(transferSubscriptions, sendInitialValues);

            Assert.IsTrue(result);

            // validate results
            for (int ii = 0; ii < transferSubscriptions.Count; ii++)
            {
                Assert.IsTrue(transferSubscriptions[ii].Created);
            }

            TestContext.Out.WriteLine("TargetSession is now SessionId={0}", targetSession.SessionId);

            // wait for some events
            await Task.Delay(kDelay).ConfigureAwait(false);

            // stop publishing
            foreach (var subscription in transferSubscriptions)
            {
                TestContext.Out.WriteLine("SetPublishingMode(false) for SessionId={0}, SubscriptionId={1}",
                                          subscription.Session.SessionId, subscription.Id);
                subscription.SetPublishingMode(false);
            }

            // validate expected counts
            for (int jj = 0; jj < kTestSubscriptions; jj++)
            {
                TestContext.Out.WriteLine("Subscription {0}: OriginCounts {1}, TargetCounts {2} ",
                                          jj, originSubscriptionCounters[jj], targetSubscriptionCounters[jj]);
                var monitoredItemCount  = transferSubscriptions[jj].MonitoredItemCount;
                var originExpectedCount = sendInitialValues && originSessionOpen ? monitoredItemCount * 2 : monitoredItemCount;
                var targetExpectedCount = sendInitialValues && !originSessionOpen ? monitoredItemCount : 0;
                if (jj == 0)
                {
                    // static nodes, expect only one set of changes, another one if send initial values was set
                    Assert.AreEqual(originExpectedCount, originSubscriptionCounters[jj]);
                    Assert.AreEqual(targetExpectedCount, targetSubscriptionCounters[jj]);
                }
                else
                {
                    // dynamic nodes, expect only one set of changes, another one if send initial values was set
                    Assert.LessOrEqual(originExpectedCount, originSubscriptionCounters[jj]);
                    Assert.LessOrEqual(targetExpectedCount, targetSubscriptionCounters[jj]);
                }
            }

            // close sessions
            targetSession.Close();
            if (originSessionOpen)
            {
                originSession.Close();
            }

            // cleanup
            File.Delete(filePath);
        }