ssisPackage.Execute (false, null, executionParameter) times out - ssis

I am trying to execute a package programmatically. The SSIS packages were deployed using the Project deployment model. I used the following as the example:
http://microsoft-ssis.blogspot.com/2013/01/call-ssis-2012-package-within-net.html
// Connection to the database server where the packages are located
SqlConnection ssisConnection = new SqlConnection
(#"Data Source=SSIS_SERVER;Initial Catalog=master;
Integrated Security=SSPI;");
// SSIS server object with connection
IntegrationServices ssisServer = new IntegrationServices(ssisConnection);
// The reference to the package which you want to execute
// (Note: formatted for ease of reading)
PackageInfo ssisPackage = ssisServer
.Catalogs["SSISDB"]
.Folders["DEV_FOLDER"]
.Projects["TestParentChildDeployment"]
.Packages["Child.dtsx"];
// Add execution parameter to override the default asynchronized execution.
//If you leave this out the package is executed asynchronized
//Collection<PackageInfo.ExecutionValueParameterSet> executionParameter
// = new Collection<PackageInfo.ExecutionValueParameterSet>();
var executionParameter = new Collection<PackageInfo
.ExecutionValueParameterSet>();
executionParameter.Add
(new PackageInfo.ExecutionValueParameterSet
{
ObjectType = 50
, ParameterName = "SYNCHRONIZED"
, ParameterValue = 1
}
);
// Get the identifier of the execution to get the log
long executionIdentifier = ssisPackage.Execute (false, null, executionParameter); // Times out here <<<<
Here is the error: Message=Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding.
It runs successfully once in a while, but more often than not, it fails. Any ideas?

Here is my solution. Instead of calling the package synchronously, call is asynchronously and use a ManualResetEvent in the calling code to block the main thread until the package completes.
namespace Anthony.Staging.Integration.Tests
{
using System;
using System.Data;
using System.Data.SqlClient;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using Microsoft.SqlServer.Management.Common;
using Microsoft.VisualStudio.TestTools.UnitTesting;
//Add references via %WINDIR%\assembly\GAC_MSIL\:
/* Microsoft.SqlServer.ConnectionInfo
* Microsoft.SqlServer.Management.InterationServices
* Microsoft.SqlServer.Management.Sdk.Sfc
* Microsoft.SqlServer.Smo
*/
using Microsoft.SqlServer.Management.IntegrationServices;
[TestClass]
public class ConnectionTests
{
private const string connectionString = #"Data Source=Anthony\MSSQL11;Initial Catalog=SSISDB;Integrated Security=SSPI;";
private static SqlConnection connection;
private static ServerConnection conn;
private static IntegrationServices ssis;
private static string catalog = "SSISDB";
private static string folder = "Anthony.Integration";
[TestInitialize]
public void MyTestInitialize()
{
connection = new SqlConnection(connectionString);
ssis = new IntegrationServices(connection);
}
[TestMethod]
public void CanConnect()
{
Assert.IsNotNull(connection);
Assert.IsTrue(connection.State == ConnectionState.Open);
}
[TestMethod]
public void CanGetKnownPackage()
{
try
{
var package = this.GetPackage(catalog, folder, "Anthony.Staging", "_Extract_Full.dtsx");
Assert.IsNotNull(package);
}
catch (Exception ex)
{
Assert.Fail(ex.Message);
}
}
[TestMethod]
public void CanExecuteKnownPackage()
{
const int MAX_RETRIES = 20;
const int RETRY_INTERVAL_SECONDS = 10;
const int OPERATION_TIMEOUT_MINUTES = 10;
// get the package from the SSISCatalog and start it asynchronously
// because starting it synchronously will time out after 30 seconds.
var package = this.GetPackage(catalog, folder, "Anthony.Staging", "_Extract_Full.dtsx");
var executionIdentifier = package.Execute(false, null);
// block the main thread and kick off a timer immediately which checks execution status for an ssis execution identifier.
var mre = new ManualResetEvent(false);
var statusChecker = new StatusChecker(executionIdentifier, MAX_RETRIES);
var timer = new Timer(statusChecker.CheckStatus, new StatusCheckerState(mre), new TimeSpan(0, 0, 0), new TimeSpan(0, 0, RETRY_INTERVAL_SECONDS));
WaitHandle.WaitAny(new WaitHandle[] { mre }, (int)new TimeSpan(0, OPERATION_TIMEOUT_MINUTES, 0).TotalMilliseconds, false);
mre.Dispose();
timer.Dispose();
// get the results
var execution = ssis.Catalogs.Single(x => x.Name.Equals(catalog)).Executions.Single(x => x.Id.Equals(executionIdentifier));
var errors = execution.Messages.Where(m => m.MessageType == 120).Select(m => m.Message);
var warnings = execution.Messages.Where(m => m.MessageType == 110).Select(m => m.Message);
Assert.AreEqual(0, errors.Count());
Assert.AreEqual(Operation.ServerOperationStatus.Success, execution.Status);
}
class StatusCheckerState
{
public StatusCheckerState(ManualResetEvent waitHandle)
{
this.WaitHandle = waitHandle;
}
public ManualResetEvent WaitHandle { get; private set; }
}
class StatusChecker
{
private readonly long executionIdentifier;
private int invokeCount;
private ManualResetEvent waitHandle;
private readonly int maximumCount;
public StatusChecker(long executionIdentifier, int maxCount)
{
this.executionIdentifier = executionIdentifier;
invokeCount = 0;
maximumCount = maxCount;
}
// This method is called by the timer delegate.
public void CheckStatus(object state)
{
var localState = ((StatusCheckerState)state);
this.waitHandle = localState.WaitHandle;
if (invokeCount > 0)
{
Debug.WriteLine("Retry attempt: {0}", invokeCount);
}
invokeCount++;
if (invokeCount == maximumCount)
{
// Reset the counter and signal Main.
invokeCount = 0;
waitHandle.Set();
}
var execution = new IntegrationServices(connection).Catalogs.Single(x => x.Name.Equals(catalog)).Executions.Single(x => x.Id.Equals(executionIdentifier));
Debug.WriteLine("Status of execution " + executionIdentifier + " is " + execution.Status);
if (execution.Status == Operation.ServerOperationStatus.Success)
{
// Reset the counter and signal Main.
invokeCount = 0;
waitHandle.Set();
}
}
}
[TestCleanup]
public void MyTestCleanup()
{
if(connection.State == ConnectionState.Open)
connection.Close();
ssis = null;
}
private PackageInfo GetPackage(string catalog, string folder, string project, string package)
{
if (ssis.Catalogs.Contains(catalog))
{
var cat = ssis.Catalogs[catalog];
if (cat.Folders.Contains(folder))
{
var fold = cat.Folders[folder];
if (fold.Projects.Contains(project))
{
var proj = fold.Projects[project];
if (proj.Packages.Contains(package))
{
var pkg = proj.Packages[package];
return pkg;
}
}
}
}
throw new Exception("Cannot find package!");
}
}
}

Here is some code to solve the timeout... it's a bit dirty, but works great:
// Get the identifier of the execution to get the log
long executionIdentifier = ssisPackage.Execute(false, null, executionParameter);
/****
* This is a shameful workaround to not having a timeout override
* for PackageInfo.Execute.
****/
ExecutionOperation executionOperation = ssisServer.Catalogs["SSISDB"].Executions[executionIdentifier];
while (!(executionOperation.Completed))
{
executionOperation.Refresh();
System.Threading.Thread.Sleep(5000);
}
Source:
https://social.msdn.microsoft.com/Forums/sqlserver/en-US/7f0967af-fdeb-4040-9c57-2fe14f2291b5/timeout-after-30-seconds-when-executing-package-via-net?forum=sqlintegrationservices

Related

I want to create highchart widget by Eclipse RAP and i follow "RAP/Custom Widgets FAQ",but there is error?

i want to create some highchart widget by Eclipse RAP ,and i follow the official guide like this
handlejs:
var CKEDITOR_BASEPATH = "rwt-resources/";
(function(){
'use strict';
rap.registerTypeHandler( "rap.sunline.HighCharts", {
factory : function( properties ) {
var parent = rap.getObject( properties.parent );
// var element = document.createElement( "div" );
// parent.append( element );
// $(element).html("askldfjaskljdk");
return {};
}
});
}());
widget.java:
public class HightChartComposite extends Composite {
private static final String RESOURCES_PATH = "resources/";
private static final String REGISTER_PATH = "hightcharts/";
private static final String[] RESOURCE_FILES = { "jquery-2.1.0.min.js", "highcharts.js","ChartPaintListener.js" };
private static final String REMOTE_TYPE = "rap.sunline.HightCharts";
private final RemoteObject remoteObject;
private final OperationHandler operationHandler = new AbstractOperationHandler() {
#Override
public void handleSet(JsonObject properties) {
// JsonValue textValue = properties.get("text");
// if (textValue != null) {
// text = textValue.asString();
// }
}
};
public HightChartComposite(Composite parent, int style) {
super(parent, style);
registerResources();
loadJavaScript();
Connection connection = RWT.getUISession().getConnection();
remoteObject = connection.createRemoteObject(REMOTE_TYPE);
remoteObject.setHandler(operationHandler);
remoteObject.set("parent", WidgetUtil.getId(this));
}
private void registerResources() {
ResourceManager resourceManager = RWT.getResourceManager();
boolean isRegistered = resourceManager.isRegistered(REGISTER_PATH + RESOURCE_FILES[0]);
if (!isRegistered) {
try {
for (String fileName : RESOURCE_FILES) {
register(resourceManager, fileName);
}
} catch (IOException ioe) {
throw new IllegalArgumentException("Failed to load resources", ioe);
}
}
}
private void loadJavaScript() {
JavaScriptLoader jsLoader = RWT.getClient().getService(JavaScriptLoader.class);
ResourceManager resourceManager = RWT.getResourceManager();
jsLoader.require(resourceManager.getLocation(REGISTER_PATH + "jquery-2.1.0.min.js"));
jsLoader.require(resourceManager.getLocation(REGISTER_PATH + "highcharts.js"));
jsLoader.require(resourceManager.getLocation(REGISTER_PATH + "ChartPaintListener.js"));
}
private void register(ResourceManager resourceManager, String fileName) throws IOException {
ClassLoader classLoader = HightChartComposite.class.getClassLoader();
InputStream inputStream = classLoader.getResourceAsStream(RESOURCES_PATH + fileName);
try {
resourceManager.register(REGISTER_PATH + fileName, inputStream);
} finally {
inputStream.close();
}
}
// //////////////////
// overwrite methods
#Override
public void setLayout(Layout layout) {
throw new UnsupportedOperationException("Cannot change internal layout of CkEditor");
}
}
the error is occur:
Uncaught Error: Operation "create" on target "r6" of type "null" failed:
No Handler for type rap.sunline.HightCharts
Properties:
parent = w5
and i have a question about this , what differents from extends Canvas and Composite;
You forget to implement setters in your javascript code.
The created object is stored by the framework under its object id. This object has to implement setter methods that match the properties defined in the handler, which will then be called when the server sends a set operation for a given property.

How to update data continuously in UI text box control using windows phone application

Im developing a small Tcp Client Socket application in windows phone. Actually i have a text box, in that whatever the data received from a TCP server, should update continuously in UI text box control.
while (val)
{
result = Receive();
Dispatcher.BeginInvoke((Action)(() =>
{
txtOutput.Text += result;
}));
}
Here in above code, method receive() will receive string data and should update in textbox control but it is not happening,no data is updating to it.
Can any one suggest, how can i resolve this.
Just telling you what i have been advised, "avoid Dispatcher, CoreDispatcher, etc. There are always better solutions."
Below is the piece of code worked for me for both wp8 and wp8.1 WinRT app,
IProgress<object> progress = new Progress<object>(_ => UpdateTicker());
Task.Run(async () =>
{
while (val)
{
progress.Report(null);
}
});
where UpdateTicker() method contains your instructions, in this case...
public void UpdateTicker()
{
result = Receive();
txtOutput.Text += result;
}
Hope this helps...
Thanks for everyone, who given a valuable response for my post.
Hi Nishchith,
I tried your code, but it dint works for me
Here is my logic used to update textbox continuously with data received from TCP server.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Navigation;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Shell;
using PhoneApp3.Resources;
using System.Net.Sockets;
using System.Threading;
using System.Text;
using Windows.Phone.Networking;
using System.Threading.Tasks;
namespace PhoneApp3
{
public partial class MainPage : PhoneApplicationPage
{
Socket _socket = null;
static ManualResetEvent _clientDone = new ManualResetEvent(false);
const int TIMEOUT_MILLISECONDS = 1000;
const int MAX_BUFFER_SIZE = 2048;
const int ECHO_PORT = 9055; // The Echo protocol uses port 7 in this sample
const int QOTD_PORT = 49152; // The Quote of the Day (QOTD) protocol uses port 17 in this sample
string result = string.Empty;
public MainPage()
{
InitializeComponent();
}
private void btnEcho_Click(object sender, RoutedEventArgs e)
{
SocketClient client = new SocketClient();
Connect(txtRemoteHost.Text, ECHO_PORT);
//close();
}
public void Connect(string hostName, int portNumber)
{
DnsEndPoint hostEntry = new DnsEndPoint(hostName, portNumber);
_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
SocketAsyncEventArgs socketEventArg = new SocketAsyncEventArgs();
socketEventArg.RemoteEndPoint = hostEntry;
socketEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(delegate(object s, SocketAsyncEventArgs e)
{
result = e.SocketError.ToString();
_clientDone.Set();
});
_clientDone.Reset();
Thread.Sleep(2000);
_socket.ConnectAsync(socketEventArg);
Thread.Sleep(5000);
_clientDone.WaitOne(TIMEOUT_MILLISECONDS);
bool val;
if (result == "Success")
{
val = true;
}
else
{
val = false;
}
IProgress<object> progress = new Progress<object>(_ => UpdateTicker());
Task.Run(async () =>
{
while (val)
{
progress.Report(null);
}
});
}
public void UpdateTicker()
{
result = Receive();
string[] strsplit = result.Split(' ');
txtOutput.Text = strsplit[1];
}
public string Receive()
{
string response = "Operation Timeout";
if (_socket != null)
{
SocketAsyncEventArgs socketEventArg = new SocketAsyncEventArgs();
socketEventArg.RemoteEndPoint = _socket.RemoteEndPoint;
socketEventArg.SetBuffer(new Byte[MAX_BUFFER_SIZE], 0, MAX_BUFFER_SIZE);
socketEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(delegate(object s, SocketAsyncEventArgs e)
{
if (e.SocketError == SocketError.Success)
{
// Retrieve the data from the buffer
response = Encoding.UTF8.GetString(e.Buffer, e.Offset, e.BytesTransferred);
response = response.Trim('\0');
}
else
{
response = e.SocketError.ToString();
}
_clientDone.Set();
});
_clientDone.Reset();
Thread.Sleep(1000);
_socket.ReceiveAsync(socketEventArg);
Thread.Sleep(1000);
_clientDone.WaitOne(TIMEOUT_MILLISECONDS);
}
else
{
response = "Socket is not initialized";
}
return response;
}
public void Close()
{
if (_socket != null)
{
_socket.Close();
}
}
}
}

Connection pool connections consumed when in TransactionScope

Can someone explain why we are experiencing a total consumption of the connection pool when performing queries inside TransactionScope resulting in
System.InvalidOperationException: Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached.
I have reduced our problem to the following:
SomeNonTransactionalCode()
{
// This code will execute with just one connection to the database
// and complete without exception
List<BusinessEntity> beList;
for (int i = 0; i < 101; i++)
{
BusinessEntityRepository beRepo = new BusinessEntityRepository();
beList = beRepo.ReadAll().ToList();
}
}
SomeTransactionalCode()
{
// This code will cause the connections to the database to increment
// with every iteration eventually timing out after 100 connections
using (TransactionScope transactionScope = new TransactionScope())
{
List<BusinessEntity> beList;
for (int i = 0; i < 101; i++)
{
BusinessEntityRepository beRepo = new BusinessEntityRepository();
beList = beRepo.ReadAll().ToList();
}
transactionScope.Complete();
}
}
EDIT
After Omer's answer below I think the problem is explained better like this:
SomeNonTransactionalCode()
{
// This code will execute with just one connection to the database
List<BusinessEntity1> be1List;
BusinessEntity1Repository be1Repo = new BusinessEntity1Repository();
be1List = be1Repo .ReadAll().ToList();
List<BusinessEntity2> be2List;
BusinessEntity2Repository be2Repo = new BusinessEntity2Repository();
be2List = be2Repo .ReadAll().ToList();
List<BusinessEntity3> be3List;
BusinessEntity3Repository be3Repo = new BusinessEntity3Repository();
be3List = be3Repo.ReadAll().ToList();
}
SomeTransactionalCode()
{
// This code will cause three seperate connections to the database
using (TransactionScope transactionScope = new TransactionScope())
{
// note this is simplified - the code below could be in unknown nested
// methods make creating of the repos prior to calling not possible
List<BusinessEntity1> be1List;
BusinessEntity1Repository beRepo1 = new BusinessEntity1Repository();
be1List = be1Repo.ReadAll().ToList();
List<BusinessEntity2> be2List;
BusinessEntity2Repository beRepo2 = new BusinessEntity2Repository();
be2List = be2Repo.ReadAll().ToList();
List<BusinessEntity3> be3List;
BusinessEntity3Repository beRepo3 = new BusinessEntity3Repository();
be3List = be3Repo.ReadAll().ToList();
transactionScope.Complete();
}
}
Surely this is not expected behaviour? I have read nothing that explains why this might be happening. I can only assume it is something to do with how we have implemented our repositories. Hopefully the following will give a good enough description of the implementation.
public class BusinessEntityRepository
{
private BusinessEntityDal Dal { get; set; }
public BusinessEntityRepository()
{
this.Dal = new BusinessEntityDal ();
}
public IQueryable<BusinessEntity> ReadAll()
{
IQueryable<BusinessEntity> query = null;
if (Dal != null)
{
query = Dal.ReadAll();
}
//-Return
return query;
}
}
public class BusinessEntityDal : BaseDal
{
public IQueryable<BusinessEntity> ReadAll()
{
var result = from de in this.DC.BusinessEntityTable
select new BusinessEntity
{
Property1 = Column1,
Property2 = Column2,
// etc...
};
//-Return
return (result);
}
}
public abstract class BaseDal
{
protected OurDataContext DC;
public BaseDal()
{
// create a DataContext
this.DC = new OurDataContext();
}
}
public class OurDataContext : System.Data.Linq.DataContext
{
private static readonly string _cn = // some static connection string taken from web.config
public OurDataContext()
: base(OurDataContext._cn)
{
}
}
Our connection string is fairly conventional and leaves the number of connections in the pool at the default 100 (hence the 101 iterations to test the issue in my code above).
You are creating new DataContext references inside the for loop.
for (int i = 0; i < 101; i++)
{
BusinessEntityRepository beRepo = new BusinessEntityRepository();
beList = beRepo.ReadAll().ToList();
}
It is keeping all those in different transactions. If you just put repo init code outside the for loop and perform all operations in one context, it will be fine.
using (TransactionScope transactionScope = new TransactionScope())
{
List<BusinessEntity> beList;
BusinessEntityRepository beRepo = new BusinessEntityRepository();
for (int i = 0; i < 101; i++)
{
beList = beRepo.ReadAll().ToList();
}
//do some other things with same context
transactionScope.Complete();
}

SSIS Scripting Component: Get child records for creating Object

Got it working - Posted My solution below but will like to know if there is better way
Hello All
I am trying to create Domain Event for a newly created (after migration) domain object in my database.
for Objects without any internal child objects it worked fine by using Script Component. The problem is in how to get the child rows to add information to event object.
Ex. Customer-> Customer Locations.
I am creating Event in Script Component- as tranformation- (have reference to my Domain event module) and then creating sending serialized information about event as a column value. The input rows currently provide data for the parent object.
Please advise.
Regards,
The Mar
Edit 1
I would like to add that current I am doing processsing in
public override void Input0_ProcessInputRow(Input0Buffer Row)
I am looking for something like create a a data reader in this function
loop through data rows -> create child objecta nd add it to parent colelction
Still on google and PreExecute and ProcessInput Seems something to look at .
This is my solution. I am a total newbie in SSIS , so this may not be the best solution.
[Microsoft.SqlServer.Dts.Pipeline.SSISScriptComponentEntryPointAttribute]
public class ScriptMain : UserComponent
{
IDTSConnectionManager100 connectionManager;
SqlCommand cmd = null;
SqlConnection conn = null;
SqlDataReader reader = null;
public override void AcquireConnections(object Transaction)
{
try
{
connectionManager = this.Connections.ScriptConnectionManager;
conn = connectionManager.AcquireConnection(Transaction) as SqlConnection;
// Hard to debug failure- better off logging info to file
//using (StreamWriter outfile =
// new StreamWriter(#"f:\Migration.txt"))
//{
// outfile.Write(conn.ToString());
// outfile.Write(conn.State.ToString());
//}
}
catch (Exception ex)
{
//using (StreamWriter outfile =
// new StreamWriter(#"f:\Migration.txt"))
//{
// outfile.Write(" EEEEEEEEEEEEEEEEEEEE"+ ex.ToString());
//}
}
}
public override void PreExecute()
{
base.PreExecute();
cmd = new SqlCommand("SELECT [CustomerLocation fields] FROM customerlocationView where custid=#CustId", conn);
cmd.Parameters.Add("CustId", SqlDbType.UniqueIdentifier);
}
public override void PostExecute()
{
base.PostExecute();
/*
Add your code here for postprocessing or remove if not needed
You can set read/write variables here, for example:
Variables.MyIntVar = 100
*/
}
public override void Input0_ProcessInputRow(Input0Buffer Row)
{
Collection<CustomerLocation> locations = new Collection<CustomerLocation>();
cmd.Parameters["CustId"].Value = Row.id;
// Any error always saw that reader reamians open on connection
if (reader != null)
{
if (!reader.IsClosed)
{
reader.Close();
}
}
reader = cmd.ExecuteReader();
if (reader != null)
{
while (reader.Read())
{
// Get Child Details
var customerLocation = new CustomerLocation(....,...,...,);
customerLocation.CustId = Row.id;
locations.Add(customerLocation);
}
}
var newCustomerCreated = new NewCustomerCreated(Row.id,,...,...,locations);
var serializedEvent = JsonConvert.SerializeObject(newCustomerCreated, Formatting.Indented,
new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Objects, ReferenceLoopHandling = ReferenceLoopHandling.Ignore });
Row.SerializedEvent = serializedEvent;
Row.EventId = newCustomerCreated.EventId;
...
...
...
....
..
.
Row.Version = 1;
// using (StreamWriter outfile =
// new StreamWriter(#"f:\Migration.txt", true))
// {
// if (reader != null)
// {
// outfile.WriteLine(reader.HasRows);
//outfile.WriteLine(serializedEvent);
// }
// else
// {
// outfile.Write("reader is Null");
// }
//}
reader.Close();
}
public override void ReleaseConnections()
{
base.ReleaseConnections();
connectionManager.ReleaseConnection(conn);
}
}
One thing to note is that a different approach to create connection is to
get the connection string from connectionManager and use it to create OLEDB connection.

StructureMap DBServiceRegistry and MVC-mini-profiler?

If I use this code in each Repository class then I get SQL profiling to work but I want to move that code from each class into the class where StructureMap handles the DB.
Example of a Repository class:
public DB CreateNewContext()
{
var sqlConnection = new SqlConnection(ConfigurationManager.ConnectionStrings["connection"].ConnectionString);
var profiledConnection = ProfiledDbConnection.Get(sqlConnection);
return DataContextUtils.CreateDataContext<DB>(profiledConnection);
}
public SqlRecipeRepository(DB dataContext)
{
_db = CreateNewContext();
}
Now I want the dataContext variable to be the profiled version and so come from my DBServiceRegistry class.
Here is the DBServiceRegistry class:
public class DBServiceRegistry : Registry
{
public DBServiceRegistry()
{
var sqlConnection = new SqlConnection(ConfigurationManager.ConnectionStrings["GetMeCooking.Data.Properties.Settings.server"].ConnectionString);
var profiledConnection = ProfiledDbConnection.Get(sqlConnection);
For<DB>().HybridHttpOrThreadLocalScoped().Use(() => DataContextUtils.CreateDataContext<DB>(profiledConnection));
//Original method just had this:
//For<DB>().HybridHttpOrThreadLocalScoped().Use(() => new DB());
}
}
This code does not cause any errors but I don't get the SQL profiling, what am I doing wrong?
The comment is correct, by creating the sql connection outwith the For line, you are overriding the scope command.
Far better to encapsulate the whole lot into an anonymous delegate
using System.Configuration;
using System.Data.SqlClient;
using System.Threading.Tasks;
using StructureMap;
using StructureMap.Configuration.DSL;
using Xunit;
public class DBServiceRegistry : Registry
{
private string connString = ConfigurationManager.ConnectionStrings["GetMeCooking.Data.Properties.Settings.server"].ConnectionString;
public DBServiceRegistry()
{
For<DB>().HybridHttpOrThreadLocalScoped().Use(
() =>
{
var sqlConnection = new SqlConnection(connString);
var profiledConnection = new StackExchange.Profiling.Data.ProfiledDbConnection(sqlConnection, MiniProfiler.Current);
return DataContextUtils.CreateDataContext<DB>(profiledConnection);
});
}
}
You can use unit tests to verify that the scope is correct (test syntax is xunit.net)
public class DBRegistryTests : IDisposable
{
private Container container;
public DBRegistryTests()
{
// Arrange (or test setup)
container = new Container(new DBServiceRegistry());
}
[Fact]
public void ConnectionsAreSameInThread()
{
// Create two connections on same thread
var conn1 = container.GetInstance<DB>();
var conn2 = container.GetInstance<DB>();
// Assert should be equal because hybrid thread is scope
// and test executes on same thread
Assert.Equal(conn1, conn2);
// Other assertions that connection is profiled
}
[Fact]
public void ConnectionAreNotSameInDifferentThreads()
{
var conn1 = container.GetInstance<DB>();
// Request second connection from a different thread
// (for < c# 4.0 use Thread instead of task)
var conn2 = new Task<DB>(() => this.container.GetInstance<DB>());
conn2.Start();
conn2.Wait();
// Assert that request from two different threads
// are not the same
Assert.NotEqual(conn1, conn2.Result);
}
public void Dispose()
{
// Test teardown
container.Dispose();
}
}