Here is my basic situation. I'm trying to use NHibernate to get information from a database, create some objects based off the mappings, serialize, them, and the move the serialized object on to a flash component. No build errors are going off, but when I return the 'serialized' object it keeps returning null. Upon inserting some breakpoints and stepping through, I realized where everything was going south.
I put my break point in here:
var tasks = (List<CSH_Task>)persistanceManager.RetrieveAll<CSH_Task>(SessionAction.BeginAndEnd);
And it goes into my PersistanceManager class, successfully passing my CSH_Task:
public IList<T> RetrieveAll<T>(SessionAction sessionAction)
{
/* Note that NHibernate guarantees that two object references will point to the
* same object only if the references are set in the same session. For example,
* Order #123 under the Customer object Able Inc and Order #123 in the Orders
* list will point to the same object only if we load Customers and Orders in
* the same session. If we load them in different sessions, then changes that
* we make to Able Inc's Order #123 will not be reflected in Order #123 in the
* Orders list, since the references point to different objects. That's why we
* maintain a session as a member variable, instead of as a local variable. */
// Open a new session if specified
if ((sessionAction == SessionAction.Begin) || (sessionAction == SessionAction.BeginAndEnd))
{
m_Session = m_SessionFactory.OpenSession();
}
// Retrieve all objects of the type passed in
ICriteria targetObjects = m_Session.CreateCriteria(typeof(T));
IList<T> itemList = targetObjects.List<T>();
// Close the session if specified
if ((sessionAction == SessionAction.End) || (sessionAction == SessionAction.BeginAndEnd))
{
m_Session.Close();
m_Session.Dispose();
}
// Set return value
return itemList;
}
Which is straight from an older example of NHibernate(I'm extremely new to it)
And it drops me into a "No Source Available" Page, which lists this
Call stack location:
Iesi.Collections.DLL!Iesi.Collections.Generic.HashedSet.HashedSet()
Line 18
Source file information:
Locating source for
'd:\CSharp\NH\NH_Hg\nhibernate\src\Iesi.Collections\Generic\HashedSet.cs'.
Checksum: MD5 {d3 1c 6c 95 94 c0 cb d4 b5 8d 8c 42 c5 4a 37 b2}
The file 'd:\CSharp\NH\NH_Hg\nhibernate\src\Iesi.Collections\Generic\HashedSet.cs'
does not exist.
Looking in script documents for 'd:\CSharp\NH\NH_Hg\nhibernate\src\Iesi.Collections\Generic\HashedSet.cs'...
Looking in the projects for 'd:\CSharp\NH\NH_Hg\nhibernate\src\Iesi.Collections\Generic\HashedSet.cs'.
The file was not found in a project.
Looking in directory 'C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\crt\src\'...
Looking in directory 'C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\atlmfc\src\mfc\'...
Looking in directory 'C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\atlmfc\src\atl\'...
Looking in directory 'C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\atlmfc\include\'... Looking in directory 'C:\Users\tackiean\Desktop\'...
Looking in directory 'E:\SmartMC\NHibernate\Required_Bins\'...
Source was found at 'E:\SmartMC\NHibernate\Required_Bins\HashedSet.cs'.
Determining whether the checksum matches for the following locations:
1:E:\SmartMC\NHibernate\Required_Bins\HashedSet.cs Checksum: MD5 {40 1b
39 7e 8f 4a 3f 6 11 41 88 70 9e 8f 8 f1} Checksum doesn't match.
The debug source files settings for the active solution indicate that the debugger will not ask the user to find the file: d:\CSharp\NH\NH_Hg\nhibernate\src\Iesi.Collections\Generic\HashedSet.cs.
The debugger could not locate the source file 'd:\CSharp\NH\NH_Hg\nhibernate\src\Iesi.Collections\Generic\HashedSet.cs'.
If I keep stepping through it returns to my code, then back here listing a virtually identical message about DictionarySet.cs
I am not the one who downloaded NHibernate for this project on this machine in the first place, but I would have imagined that if HashedSet.cs/DictionarySet.cs were required for it to work, they would have been included by default no? I've spent the last about 7 hours today looking for answer to this, but am coming up empty. I have never seen an error like this before. I think its just looking for a file that NHibernate needs, and can't find, but is something else going on here? Any help would be sorely appreciated. I hope this an appropriate location/formatted legibly; I've never asked a question on here before so I hope it's not completely inappropriate.
HashedSet and DictionarySet are part of Iesi.Collections, a collection library included with NHibernate. The binary package of NHibernate usually includes the .pdb files, that contain the debug information of the assemblies. When the debugger wants to open the source files, it can't find them on your machine, because the included source paths are that of the package maintainers.
If you wish to, you can download the NHibernate sources at GitHub and compile the assemblies by yourself. Then the debugger will automatically find the source files, when an exception occurs (do not move the source files after compilation).
You should modify your RetrieveAll method a bit, because you have to always open a session and close it somewhere. Normally, you do something like:
using (ISession sess = factory.OpenSession())
using (ITransaction tx = sess.BeginTransaction())
{
try
{
var crit = sess.CreateCriteria<T>();
var list = crit.List<T>();
// Do something with list
tx.Commit();
}
catch (Exception)
{
tx.Rollback();
}
}
If you want to return the queried list to the caller, the session will be closed. So make sure, that there are no uninitalized lazy loading proxies left in your queried list. You may read the lazy/eager loading section in the NHibernate documentation. Hope, I could help a bit with your problem.
The messages you see are your debugger trying to find the source code since you are stepping through it. The lack of that source code on your machine does not effect NHibernate runtime.
Related
I have a relatively large db that may take 1 to 2 minutes to initialise, is it possible to load a pre-populated db when using sqldelight (kotlin multiplatform) instead of initialising the db on app launch?
Yes, but it can be tricky. Not just for "Multiplatform". You need to copy the db to the db folder before trying to init sqldelight. That probably means i/o on the main thread when the app starts.
There is no standard way to do this now. You'll need to put the db file in assets on android and in a bundle on iOS and copy them to their respective folders before initializing sqldelight. Obviously you'll want to check if the db exists first, or have some way of knowing this is your first app run.
If you're planning on shipping updates that will have newer databases, you'll need to manage versions outside of just a check for the existance of the db.
Although not directly answering your question, 1 to 2 minutes is really, really long for sqlite. What are you doing? I would first make sure you're using transactions properly. 1-2 minutes of inserting data would (probably) result in a huge db file.
Sorry, but I can't add any comments yet, which would be more appropriate...
Although not directly answering your question, 1 to 2 minutes is
really, really long for sqlite. What are you doing? I would first make
sure you're using transactions properly. 1-2 minutes of inserting data
would (probably) result in a huge db file.
Alternatively, my problem due to which I had to use a pre-populated database was associated with the large size of .sq files (more than 30 MB text of INSERTs per table), and SqlDeLight silently interrupted the generation, without displaying error messages.
You'll need to put the db file in assets on android and in a bundle on
iOS and copy them to their respective folders before initializing
sqldelight.
Having to load a db from resources on both android and ios feels a lot
of work + it means the shared project wont be the only place where the
data is initialised.
Kotlin MultiPlatform library Moko-resources solves the issue of a single source for a database in a shared module. It works for KMM the same way for Android and iOS.
Unfortunately, using this feature are almost not presented in the samples of library. I added a second method (getDriver) to the expected class DatabaseDriverFactory to open the prepared database, and implemented it on the platform. For example, for androidMain:
actual class DatabaseDriverFactory(private val context: Context) {
actual fun createDriver(schema: SqlDriver.Schema, fileName: String): SqlDriver {
return AndroidSqliteDriver(schema, context, fileName)
}
actual fun getDriver(schema: SqlDriver.Schema, fileName: String): SqlDriver {
val database: File = context.getDatabasePath(fileName)
if (!database.exists()) {
val inputStream = context.resources.openRawResource(MR.files.dbfile.rawResId)
val outputStream = FileOutputStream(database.absolutePath)
inputStream.use { input: InputStream ->
outputStream.use { output: FileOutputStream ->
input.copyTo(output)
}
}
}
return AndroidSqliteDriver(schema, context, fileName)
}
}
MR.files.fullDb is the FileResource from the class generated by the library, it is associated with the name of the file located in the resources/MR/files directory of the commonMain module. It property rawResId represents the platform-side resource ID.
The only thing you need is to specify the path to the DB file using the driver.
Let's assume your DB lies in /mnt/my_best_app_dbs/super.db. Now, pass the path in the name property of the Driver. Something like this:
val sqlDriver: SqlDriver = AndroidSqliteDriver(Schema, context, "/mnt/my_best_app_dbs/best.db")
Keep in mind that you might need to have permissions that allow you to read a given storage type.
What I want to do?
I want to create and consume java objects in PowerBuilder and call methods on it. This should happen with less overhead possible.
I do not want to consume java webservices!
So I've a working sample in which I can create a java object, call a method on this object and output the result from the called method.
Everything is working as expected. I'm using Java 1.8.0_31.
But now I want to attach my java IDE (IntelliJ) to the running JVM (started by PowerBuilder) to debug the java code which gets called by PowerBuilder.
And now my question.
How do I tell PowerBuilder to add special options when starting the JVM?
In special I want to add the following option(s) in some way:
-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005
The JVM is created like following:
LONG ll_result
inv_java = CREATE JavaVM
ll_result = inv_java.CreateJavaVM("C:\Development\tms java\pbJavaTest", FALSE)
CHOOSE CASE ll_result
CASE 1
CASE 0
CASE -1
MessageBox ( "", "jvm.dll was not found in the classpath.")
CASE -2
MessageBox ( "", "pbejbclient90.jar file was not found." )
CASE ELSE
MessageBox ( "", "Unknown result (" + String (ll_result ) +")" )
END CHOOSE
In the PowerBuilder help I found something about overriding the static registry classpath. There is something written about custom properties which sounds like what I'm looking for.
But there's no example on how to add JVM options to override default behavior.
Does anyone have a clue on how to tell PowerBuilder to use my options?
Or does anyone have any advice which could guide me in the right direction?
Update 1
I found an old post which solved my initial issue.
If someone else want to know how it works take a look at this post:
http://nntp-archive.sybase.com/nntp-archive/action/article/%3C46262213.6742.1681692777#sybase.com%3E
Hi, you need to set some windows registry entries.
Under HKEY_LOCAL_MACHINE\SOFTWARE\Sybase\Powerbuilder\9.0\Java, there
are two folders: PBIDEConfig and PBRTConfig. The first one is used when
you run your application from within the IDE, and the latter is used
when you run your compiled application. Those two folders can have
PBJVMconfig and PBJVMprops folders within them.
PBJVMconfig is for JVM configuration options such as -Xms. You have to
specify incremental key values starting from "0" by one, and one special
key "Count" to tell Powerbuilder how many options exists to enumerate.
PBJVMprops is for all -D options. You do not need to specify -D for
PBJVMProps, just the name of the property and its value, and as many
properties as you wish.
Let me give some examples:
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\Sybase\PowerBuilder\9.0\Java\PBIDEConfig\PBJVMprops]
"java.security.auth.login.config"="auth.conf"
"user.language"="en"
[HKEY_LOCAL_MACHINE\SOFTWARE\Sybase\PowerBuilder\9.0\Java\PBRTConfig\PBJVMconfig]
"0"="-client"
"1"="-Xms128m"
"2"="-Xmx512m"
"Count"="3"
[HKEY_LOCAL_MACHINE\SOFTWARE\Sybase\PowerBuilder\9.0\Java\PBRTConfig\PBJVMprops]
"java.security.auth.login.config"="auth.conf"
"user.language"="en"
Regards,
Gokhan Demir
But now there's another issue...
PB isn't able to create EJB Proxies for my sample class which is really simple with java 1.8.0_31. They were created with the default version, which is 1.6.0_24.
public class Simple
{
public Simple()
{
}
public static String getValue()
{
return "blubber";
}
public int getInt32Value()
{
return 123456;
}
public double getDoubleVaue()
{
return 123.123;
}
public static void main(String[] args)
{
System.out.println(Simple.getValue());
}
}
The error is the following. :D
---------- Deploy: Deploy of project p_genapp_ejbclientproxy (15:35:18)
Retrieving PowerBuilder Proxies from EJB...
Generation Errors: Error: class not found: (
Deployment Error: No files returned for package/component 'Simple'. Error code: Unknown. Proxy was not created.
Done.
---------- Finished Deploy of project p_genapp_ejbclientproxy (15:35:19)
So the whole way isn't a option because we do not want to change the JAVA settings in PB back and forth just to generate new EJB Proxies for changed JAVA objects in the future...
So one option to test will be creating COM wrappers for JAVA classes to use them in PB...
I am trying to replicate the tree style view in Source Safe into my application in vb.net... I have already added the COM objects and connected to Source Safe database successfully... What i need is the method to populate the tree view with Source Safe files.... The logic to populate it and other necessary info... Can anyone HELP me???
I have inserted the tree view in my form
I have added the COM object for source safe
I have connected to source safe 'srcsafe.ini' file for database connection
I know i can use recursive program to fetch all the files in source safe
The only problem is i don't know about source safe functions. I have tried the MSDN website and read about all the properties of source safe. But how i use them, need some example.
And about flags in source safe, what i need to do to those flags when i perform the source safe functions from my application .
And how can i make the user restrictions like in source safe to my application
]
Here is documentation on VSS Automation. I had another link but it appears to be broken now.
http://msdn.microsoft.com/en-us/library/bb509341(v=vs.80).aspx
To work with VSS you would first create an instance of the VSSDatabaseClass class and call its Open method:
Dim vssDatabase As String = "\\server\somepath\srcsafe.ini"
Dim ssdb As new VSSDatabaseClass()
ssdb.Open(vssDatabase, userName, password)
The two methods that you will use most often are get_VSSItem() and get_Items(). These will return a singile VSSItem (which is a file or project) or a collection of items. So to get the root project of the database, you would use code such as this:
Dim root As IVSSItem = ssdb.getVSSItem("$/", False)
The Type property of a VSSItem indicates if the item is a project or file. If it is a project, you can get its child items using get_Items:
If root.Type = 0 Then 'Type = 0 means it's a project
Dim items As IVSSItems = root.get_Items(False)
For Each item As IVSSItem In items
If item.Type = 0 Then
'item is a project
Else
'item is a file
End If
Next
End If
I hope this gets you started.
I have a Custom Action project that has various CA's used by installers that my company creates, a few of those are used to manipulate the IIs7 through the Microsoft.Web.Administration API.
I added a new custom action called SetApplicationAutoStart the the class containing IIs related CA's. This custom action is used to set the autoStart attribute that forces the IIs to preload and start WCF services so that initial response time will be shorter.
After adding this action an existing CA called SetAppPoolLoadUserProfileTrue stopped working. This CA forces that setting on a site to true, even if the default site on the computer has been changed so that this setting is false, so we really need it to work.
The log files contains the following lines when the action fails.
MSI (s) (A0:18) [15:02:43:639]: Executing op: ActionStart(Name=SetAppPoolLoadUserProfileTrue,,)
Action 15:02:43: SetAppPoolLoadUserProfileTrue.
MSI (s) (A0:18) [15:02:43:641]: Executing op: CustomActionSchedule(Action=SetAppPoolLoadUserProfileTrue,ActionType=3073,Source=BinaryData,Target=SetAppPoolLoadUserProfileTrue,CustomActionData=AppPoolName=xxxxx)
MSI (s) (A0:18) [15:02:43:670]: Creating MSIHANDLE (377) of type 790536 for thread 50712
MSI (s) (A0:C8) [15:02:43:670]: Invoking remote custom action. DLL: C:\Windows\Installer\MSIBD82.tmp, Entrypoint: SetAppPoolLoadUserProfileTrue
CustomAction SetAppPoolLoadUserProfileTrue returned actual error code 1154 (note this may not be 100% accurate if translation happened inside sandbox)
MSI (s) (A0:C8) [15:02:43:673]: Closing MSIHANDLE (377) of type 790536 for thread 50712
MSI (s) (A0:18) [15:02:43:674]: Note: 1: 1723 2: SetAppPoolLoadUserProfileTrue 3: SetAppPoolLoadUserProfileTrue 4: C:\Windows\Installer\MSIBD82.tmp
Error 1723. There is a problem with this Windows Installer package. A DLL required for this install to complete could not be run. Contact your support personnel or package vendor. Action SetAppPoolLoadUserProfileTrue, entry: SetAppPoolLoadUserProfileTrue, library: C:\Windows\Installer\MSIBD82.tmp
MSI (s) (A0:18) [15:20:25:139]: Product: xxxxxxx -- Error 1723. There is a problem with this Windows Installer package. A DLL required for this install to complete could not be run. Contact your support personnel or package vendor. Action SetAppPoolLoadUserProfileTrue, entry: SetAppPoolLoadUserProfileTrue, library: C:\Windows\Installer\MSIBD82.tmp
Action ended 15:20:25: InstallFinalize. Return value 3.
This looks like a problem extracting the dotnet PE from the PE for this action. All other CA's in the binary work properly including the new one.
Same thing happened to me. "galets" was already pointing in the right direction, setting me on track (no rep to upvote, sorry).
Short version:
MakeSfxCA produces native dlls not following the PE / COFF spec leading to the observed behaviour.
Long version:
Construct a CA, e.g. "HavocAction", having three exported entry points (i.e. marked with "CustomAction" attribute), named "HavocEntryPointa", "HavocEntryPointB", "HavocZappEntryPoint" (mind the exact spelling). The methods may just return "ActionResult.Success".
Come up with simple setups, a) invoking just "HavocEntryPointa", b) invoking just "HavocEntryPointB"
==> Setup "a)" will work, Setup "b)" will fail
Uncomment the "CustomAction" attribute on "HavocZappEntryPoint" and the behaviour is inverted, i.e.
==> Setup "a)" will fail, Setup "b)" will work
Further analysis
When you dump the wrapped CA.dll-file with
dumpbin /Exports HavocAction.CA.dll
you get something like (excerpt)
125 7C 00003A36
126 7D 00003A4C HavocEntryPointa
127 7E 00003A62 HavocEntryPointB
128 7F 00003A78 HavocZappEntryPoint
129 80 000042FC zzzEmbeddedUIHandler
130 81 000043B8 zzzInitializeEmbeddedUI
131 82 0000467F zzzShutdownEmbeddedUI
132 83 00003AA5 zzzzInvokeManagedCustomActionOutOfProcW
This is wrong (search for "pecoff_v83.docx", cf. Exported DLL functions not ordered lexically?). The entries are supposed to be sorted (by ASCII) in order to do a binary search when loading methods from the dll (the entries "HavocEntryPointa" and "HavocEntryPointB" are interchanged).
My educated guess is, when loading code from the dll the binary search fails, resulting in the error. Due to the nature of a binary search, removing "HavocZappEntryPoint" inverts the effect.
Remark regarding OP
Kjartan first used "SetApplicationAutoStart" and "SetAppPoolLoadUserProfileTrue" which was not correctly exported to the CA.dll due to wrong ordering; the upper case letter "P" comes before the lower case "l" but this was interchanged by MakeSfxCA. His latter choice "ConfigureApplicationAutoStart" and "SetAppPoolLoadUserProfileTrue" is ordered conforming to the PE / COFF spec.
PS: This is http://wixtoolset.org/issues/4502 now.
Update
PPS: Starting with the WiX 3.9 RC3 release the bug fix for this issue is included; everything works as expected.
I experienced exactly the same symptom you are describing. There seems to be a problem with WiX toolset. My version of WiX tolset is 3.8, and I also had a custom action, which would not run, and changing its name fixed the problem. The SFX compiler simply compiles the broken DLL without any indication of a problem. What makes the matters worse is that in my case this was a function which was supposed to run on uninstall with Result="ignore", so I wouldn't even have any immediate indication that there is a problem after I run actual installer.
I tried experimenting to understand what exactly is the problem with the name, and did not find any satisfactory explanation. It seems to not matter where in the source code the offending function is, what is it alphabetically (e.g.: functions succeed which are before and after it alphabetically). Loading DLL into depends.exe shows that there is an export, but trying to rundll32 it fails to find that export. Changing its name fixes the problem. Also, sometimes you can add another function, and the failing one would succeed, but the one you just added fails instead.
Here's what I have done to fix the problem: I wrote a C++ program which loads the compiled custom action and verifies the export. Then I wrote a unit test, which verified all of the exports in custom action. This obviously does not fix the issue, but at least you will have a unit test failure and know that your installer is broken. Here's the c++ code if you are interested:
typedef int(__stdcall *CustomActionProc)(HANDLE);
int _tmain(int argc, _TCHAR* argv[])
{
if (argc != 3)
{
_tprintf(_T("Parameters: DLL, EntryPoint\n"));
return 1;
}
LPCTSTR dllName = argv[1];
LPCTSTR entryPoint = argv[2];
HMODULE hLib = LoadLibrary(dllName);
if (hLib == NULL)
{
_tprintf(_T("Error loading %s\n"), dllName);
return 1;
}
CustomActionProc procAddress =
(CustomActionProc) GetProcAddress(hLib, CStringA(entryPoint));
if (procAddress == NULL)
{
_tprintf(_T("Error locating entrypoint %s\n"), entryPoint);
return 1;
}
return 0;
}
And the unit test is:
[TestMethod]
public void TestCustomActionCanBeInvoked()
{
var asm1 = typeof(MyCustomActionsClass).Assembly;
var methods = asm1.GetTypes().SelectMany(t =>
t.GetMethods().Where(m => m.GetCustomAttributes(false)
.Where(a => a.GetType().Name == "CustomActionAttribute").Any()));
var binFolder = (new FileInfo(this.GetType().Assembly.Location)).DirectoryName;
var customActionsSfx = Path.Combine(binFolder, "MyCustomAction.CA.dll");
var testMsiExport = Path.Combine(binFolder, "TestMsiExport.exe");
foreach (var m in methods)
{
Trace.WriteLine("Method Name: " + m.Name);
var p = Process.Start(new ProcessStartInfo()
{
FileName = testMsiExport,
Arguments = "\"" + customActionsSfx + "\" " + m.Name,
UseShellExecute = false,
RedirectStandardOutput = true,
});
p.OutputDataReceived += (s, d) => Trace.WriteLine(d.Data);
p.BeginOutputReadLine();
p.WaitForExit();
if (p.ExitCode != 0)
{
Assert.Fail("Bad Sfx export detected! Export name: " + m.Name);
}
}
}
Hope this helps someone in my situation. It was a very frustrating day trying to nail this down.
This is actually pretty strange but after a long time searching for answers and trying lot's of different things I tried changing the name of the new CA from SetApplicationAutoStart to ConfigureApplicationAutoStart and that resulted in SetAppPoolLoadUserProfileTrue to start working properly again
for some test I need to run a data driven test with a configuration that is generated (via reflection) in the ClassInitialize method (by using reflection). I tried out everything, but I just can not get the data source properly set up.
The test takes a list of classes in a csv file (one line per class) and then will test that the mappings to the database work out well (i.e. try to get one item from the database for every entity, which will throw an exception when the table structure does not match).
The testmethod is:
[DataSource(
"Microsoft.VisualStudio.TestTools.DataSource.CSV",
"|DataDirectory|\\EntityMappingsTests.Types.csv",
"EntityMappingsTests.Types#csv",
DataAccessMethod.Sequential)
]
[TestMethod()]
public void TestMappings () {
Obviously the file is EntityMappingsTests.Types.csv. It should be in the DataDirectory.
Now, in the Initialize method (marked with ClassInitialize) I put that together and then try to write it.
WHERE should I write it to? WHERE IS THE DataDirectory?
I tried:
File.WriteAllText(context.TestDeploymentDir + "\\EntityMappingsTests.Types.csv", types.ToString());
File.WriteAllText("EntityMappingsTests.Types.csv", types.ToString());
Both result in "the unit test adapter failed to connect to the data source or read the data". More exact:
Error details: The Microsoft Jet database engine could not find the
object 'EntityMappingsTests.Types.csv'. Make sure the object exists
and that you spell its name and the path name correctly.
So where should I put that file?
I also tried just writing it to the current directory and taking out the DataDirectory part - same result. Sadly, there is limited debugging support here.
Please use the ProcessMonitor tool from technet.microsoft.com/en-us/sysinternals/bb896645. Put a filter on MSTest.exe or the associate qtagent32.exe and find out what locations it is trying to load from and at what point in time in the test loading process. Then please provide an update on those details here .
After you add the CSV file to your VS project, you need to open the properties for it. Set the Property "Copy To Output Directory" to "Copy Always". The DataDirectory defaults to the location of the compiled executable, which runs from the output directory so it will find it there.