How to add AOT objects by x++ code on D365 FO - axapta

I have a question about adding AOT objects by X++ Code on D365 FO.
The goal, is to automate creation of security duty, via x++ code, instead of doing it manually
I'm trying actually with the Following code,
public static void main (Args _args)
{
#AOT
str objectName = 'MySpecTable' ;
TreeNode nodePath = TreeNode::findNode(#TablesPath);
TreeNode nodePath1;
nodePath1 = nodePath.AOTfindChild(objectName);
if(nodePath)
{
nodePath.AOTadd(objectName);
//nodePath.AOTsave();
info("Sec privilege well added");
}
else
{
nodePath.AOTadd(objectName);
nodePath.AOTsave();
info("Table well added");
}
}
But i receive the Following error,
is there any way to achieve this goal.to be able adding them via code.
Thanks

This is not possible anymore as, compared with previous AX versions, where code and metadata was dynamically interpreted in runtime, F&O executes only pre-compiled assemblies (like any other .NET application). Same way you can't create a C# class on a running .NET assembly, you can't do it either in Finance and Operations application.
Required Security artifacts must be properly created in Visual Studio, compiled and deployed to the runtime environment (UAT, PROD or whatever), and then the security configuration itself (linking these artifacts between them or with users) is now stored in the database, so it can be done directly in the Security setup forms. It can also be exported and imported with Data entities within the standard form.
What you can do is create a Visual Studio extension to automatically create such objects, so then they can be compiled and deployed correctly.

Related

MvvmCross - how do I access SQLite in a windows store background task?

I have a store app that uses the mvvmcross sqlite plugin (community edition). This app has a periodic background task that accesses the database to get data to be shown in a live tile. I can't see how I can get access to this database from the background task. I would like to use the mvvmcross sqlite plugin in the background task, but I don't see how to initialize the mvvmcross environment properly.
If you want to initialize the full MvvmCross framework including all of your app, then you'll need to run your Setup class.
In WinRT, this could be as simple as calling:
var setup = new Setup(null /*rootFrame*/);
setup.Initialize();
although it may require you to do a little work to:
Make sure your presenter does not use the null rootFrame
Provide some other means to create a UI thread dispatcher - currently MvxStoreViewDispatcher relies on .Dispatcher access - see https://github.com/MvvmCross/MvvmCross/blob/v3.1/Cirrious/Cirrious.MvvmCross.WindowsStore/Views/MvxStoreViewDispatcher.cs - to do this, you could override InitializeViewDispatcher with something like:
protected override void InitializeViewDispatcher()
{
if (_rootFrame != null)
{
base.InitializeViewDispatcher(); return;
}
var dispatcher = new NonMainThreadDispatcher();
Mvx.RegisterSingleton<IMvxMainThreadDispatcher>(dispatcher);
}
public class NonMainThreadDispatcher : MvxMainThreadDispatcher
{
public bool RequestMainThreadAction(Action action)
{
action();
}
}
If you want to initialize less functionality than the entire framework (e.g. for memory reasons) then you can also consider creating special Setup and App classes just for your background task.
Aside> This is similar to questions like these in Android - Using MvvmCross from content providers and activities and MvvmCross initialization
I was able to solve the problem in a straightforward way. Since the background task only needed the SQLite data service from the PCL core project, I did the following:
Included a reference to the Core project.
Added the nuget packages for MvvmCross and the SQLite community plugin.
Deleted all of the files and folders added when doing the mvvmcross install: Bootstrap/, Todo-Mvvmcross/, Views/, DebugTrace.cs, and Setup.cs.
There is a current limitation in the nuget installer that requires some additional edits to the project file to handle multiple store platforms (x86, ARM, and x64), see 'Cirrius.Mvvmcross.Community.Plugins.SQLite.WindowsStore needs platform-specific dlls for X86 and ARM' on Stack Overflow for details. Make sure you put the Choose statement after the default SQLite.WindowsStore reference and you need to leave the default reference in the project file. You will also need to adjust the HintPath based on the location/names of your references.
Initialized the SQLite data service by explicitly calling the factory and creating a new instance of the data service:
var factory = new MvxStoreSQLiteConnectionFactory();
IMyDataService repository = new MyDataService(factory);
I then have access to the data service with no other overhead associated with mvvmcross.

How to class c# function in asp classic [duplicate]

After going through a number of different articles and not finding anything especially conclusive that takes me step-by-step through the process, I've come seeking help.
The Scenario
A client of mine is only proficient in development for ASP Classic. They have recently acquired an account for a site originally written in ASP.NET. They are rolling the site into something they can actively maintain, but the site originally included an image handler that took dynamically changing data regarding water levels and outputs an image containing a graphical representation of that data. The requirement is to develop a COM interop library that can be registered on the server and called with CreateObject to generate the same image's byte array for output using Response.BinaryWrite. The COM interop library must be registered at the remote site on a Windows 2000 Server, and I can't make any assumptions about their having access to regasm/gacutil to accomplish that task.
The Difficulty
I've built the class library by creating a Class Library project in Visual Studio 2010, choosing "COM Class" from the template, and inserting my code to generate a class with a single public method to return a byte array when given an integer (well, enumerator, but all the same). Unfortunately, even on my own development machine after building the library and registering (regasm) and caching the assembly (gacutil), I can't make a call through Classic ASP to instantiate the object, receiving instead an "ActiveX component can't create object" error. And, of course, at the server site, the DLL file can't be registered, the response being "Required module was not found."
Resources I've Used
I've already had a look through the following articles and haven't turned up the answers I need:
(Basic steps) Walkthrough: Creating COM Objects with Visual Basic
Build and Deploy a .NET COM Assembly
.NET COM+ Interop Component with Classic ASP
What I Need
Essentially what I need is a bit of hand-holding on a kind of step by step of what it's going to take to meet the requirements and create a COM+ interop module correctly in Visual Studio 2010. Creating the actual class object itself isn't terribly difficult.
However, none of the articles I've looked through really discuss project options or build procedures with Visual Studio 2010 or the .NET 4.0 Framework, nor have any of them really discussed if there are special considerations for deploying to older systems like Windows Server 2000 and the actual registration of the library on a system with only, say, regsvr32 on hand.
It should be fairly straightforward to get a basic .NET assembly exposed to COM - I've never tried the COM Class project template, so this is the way I've managed it in the past:
Create a new (bog standard) .NET class library using C# or VB. Define a COM interface (replace GUIDs with your own):
[ComVisible(true)]
[Guid("8999F93E-52F6-4E29-BA64-0ADC22A1FB11")]
public interface IComm
{
string GetMyGroups();
}
Now define a class that implements that interface (again, replace GUIDs with your own):
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
[GuidAttribute("C5C5A1A8-9BFB-4CE5-B42C-4E6688F6840B")]
[ProgId("Test.Comm.1")]
public class Comm : IComm
{
public string GetMyGroups()
{
var comm = new CommunicatorAPI.MessengerClass();
var groups = comm.MyGroups as IMessengerGroups;
return string.Join(", ", groups.OfType<IMessengerGroup>().Select(g => g.Name).ToArray());
}
}
The Prog ID attribute on this class is what you will use to instantiate your component from ASP.
Strongly-name the assembly (Project properties -> "Signing" tab -> "Sign the assembly" -> Create a new strong name key file using the dropdown)
Now, build the assembly, and register using Regasm - if you don't wish to register in the GAC (which i'd recommend, as not GACing keeps the deployment simpler), be sure to use the -Codebase parameter (this just adds a reg entry that tells clients where to find the assembly) - e.g:
regasm ClassLibrary2.dll /codebase "S:\Testing\ClassLibrary2\ClassLibrary2\bin\Debug\ClassLibrary2.dll"
Now you should be able to instantiate the component, and call methods on it - for example (in javascript):
var a = new ActiveXObject("Test.Comm.1");
alert(a.GetMyGroups());
When it comes to deployment, the important work that Regasm and Regsvr32 do is to write various settings into the registry, so that clients can find the COM component (based on Prog ID, or COM Class ID). All you need to do is work out what COM settings are being written when you run Regasm on your local machine, and write these to the registry on the server. You can use ProcMon to monitor what gets written to the registry when Regasm is run.
Generally speaking, you can expect to see something like this written to the registry:
[HKEY_CLASSES_ROOT\Test.Comm.1]
#="ClassLibrary2.Comm"
[HKEY_CLASSES_ROOT\Test.Comm.1\CLSID]
#="{00585504-90C8-4760-A359-67CAF08FFED1}"
[HKEY_CLASSES_ROOT\Wow6432Node\CLSID\{00585504-90C8-4760-A359-67CAF08FFED1}]
#="ClassLibrary2.Comm"
[HKEY_CLASSES_ROOT\Wow6432Node\CLSID\{00585504-90C8-4760-A359-67CAF08FFED1}\Implemented Categories]
[HKEY_CLASSES_ROOT\Wow6432Node\CLSID\{00585504-90C8-4760-A359-67CAF08FFED1}\Implemented Categories\{62C8FE65-4EBB-45e7-B440-6E39B2CDBF29}]
[HKEY_CLASSES_ROOT\Wow6432Node\CLSID\{00585504-90C8-4760-A359-67CAF08FFED1}\InprocServer32]
#="mscoree.dll"
"ThreadingModel"="Both"
"Class"="ClassLibrary2.Comm"
"Assembly"="ClassLibrary2, Version=1.0.0.0, Culture=neutral, PublicKeyToken=cf55d4e60653257a"
"RuntimeVersion"="v4.0.30319"
"CodeBase"="file:///S:/Testing/ClassLibrary2/ClassLibrary2/bin/Debug/ClassLibrary2.DLL"
[HKEY_CLASSES_ROOT\Wow6432Node\CLSID\{00585504-90C8-4760-A359-67CAF08FFED1}\InprocServer32\1.0.0.0]
"Class"="ClassLibrary2.Comm"
"Assembly"="ClassLibrary2, Version=1.0.0.0, Culture=neutral, PublicKeyToken=cf55d4e60653257a"
"RuntimeVersion"="v4.0.30319"
"CodeBase"="file:///S:/Testing/ClassLibrary2/ClassLibrary2/bin/Debug/ClassLibrary2.DLL"
[HKEY_CLASSES_ROOT\Wow6432Node\CLSID\{00585504-90C8-4760-A359-67CAF08FFED1}\ProgId]
#="Test.Comm.1"
Hope this helps :)
I have a Classic ASP web site that uses a VB6 COM object. I wanted to create a new version of the COM object using .NET instead of VB6. This is how I did it (hope this helps). I include instructions for both C# and VB.NET.
[01]
Start Visual Studio 2015 (run as admin).
Create a new "Class Library" project.
Name it: "DotNetCom"
[02] C#
Add a new class, name it "HelloCOM".
Use the following code as starting template
( visit https://msdn.microsoft.com/en-us/library/c3fd4a20.aspx for more info )
using System.Runtime.InteropServices;
namespace DotNetCom
{
[Guid("EAA4976A-45C3-4BC5-BC0B-E474F4C3C83F")]
public interface HelloCOMInterface
{
[DispId(1)]
string Hello();
}
[Guid("7BD20046-DF8C-44A6-8F6B-687FAA26FA71"),
InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface HelloCOMEvents
{
}
[Guid("0D53A3E8-E51A-49C7-944E-E72A2064F938"),
ClassInterface(ClassInterfaceType.None),
ComSourceInterfaces(typeof(HelloCOMEvents))]
public class HelloCOM : HelloCOMInterface
{
public string Hello()
{
return "Hello there!";
}
}
}
[02] VB.NET
Add a new "COM class", name it "HelloCOM".
VB.NET creates the starting template.
Add the following function to the "HelloCOM" class.
Public Function Hello() As String
Return "Hello there!"
End Function
[03] C#
Open the project properties.
Go to "Application".
Click "Assembly Information...".
Check "Make assembly COM-Visible"
Go to "Build".
Select "Platform target: x86".
Check "Register COM for interop"
[03] VB.NET
Open "MyProject".
Go to "Compile".
Select "Target CPU: x86".
[04]
Build the "DotNetCom.dll".
[05]
Open a command prompt (run as admin).
Change directory to your dll.
cd DotNetComTest\DotNetComTest\TX7NGN.COM\bin\Debug
Run RegAsm /codebase.
C:\Windows\Microsoft.NET\Framework\v4.0.30319\RegAsm DotNetComTest.dll /codebase "C:\DotNetComTest\DotNetComTest\bin\Debug\DotNetComTest.dll"
[06]
Start Component Services.
Add a new COM+ application.
Name it: "DotNetCom".
Open the "DotNetCom" properties.
Go to the "Security Tab".
UNCHECK "Enforce access checks for this application".
[07]
Add a new component.
Select "DotNetComTest.tlb" (do NOT select "DotNetComTest.dll").
[08]
Use the COM object from the Classic ASP page.
<%
Dim HelloCOM
Set HelloCOM = Server.CreateObject("DotNetCom.HelloCOM")
Response.Write HelloCom.Hello
%>

Building a COM interop library for ASP Classic using 4.0 framework and Visual Studio 2010

After going through a number of different articles and not finding anything especially conclusive that takes me step-by-step through the process, I've come seeking help.
The Scenario
A client of mine is only proficient in development for ASP Classic. They have recently acquired an account for a site originally written in ASP.NET. They are rolling the site into something they can actively maintain, but the site originally included an image handler that took dynamically changing data regarding water levels and outputs an image containing a graphical representation of that data. The requirement is to develop a COM interop library that can be registered on the server and called with CreateObject to generate the same image's byte array for output using Response.BinaryWrite. The COM interop library must be registered at the remote site on a Windows 2000 Server, and I can't make any assumptions about their having access to regasm/gacutil to accomplish that task.
The Difficulty
I've built the class library by creating a Class Library project in Visual Studio 2010, choosing "COM Class" from the template, and inserting my code to generate a class with a single public method to return a byte array when given an integer (well, enumerator, but all the same). Unfortunately, even on my own development machine after building the library and registering (regasm) and caching the assembly (gacutil), I can't make a call through Classic ASP to instantiate the object, receiving instead an "ActiveX component can't create object" error. And, of course, at the server site, the DLL file can't be registered, the response being "Required module was not found."
Resources I've Used
I've already had a look through the following articles and haven't turned up the answers I need:
(Basic steps) Walkthrough: Creating COM Objects with Visual Basic
Build and Deploy a .NET COM Assembly
.NET COM+ Interop Component with Classic ASP
What I Need
Essentially what I need is a bit of hand-holding on a kind of step by step of what it's going to take to meet the requirements and create a COM+ interop module correctly in Visual Studio 2010. Creating the actual class object itself isn't terribly difficult.
However, none of the articles I've looked through really discuss project options or build procedures with Visual Studio 2010 or the .NET 4.0 Framework, nor have any of them really discussed if there are special considerations for deploying to older systems like Windows Server 2000 and the actual registration of the library on a system with only, say, regsvr32 on hand.
It should be fairly straightforward to get a basic .NET assembly exposed to COM - I've never tried the COM Class project template, so this is the way I've managed it in the past:
Create a new (bog standard) .NET class library using C# or VB. Define a COM interface (replace GUIDs with your own):
[ComVisible(true)]
[Guid("8999F93E-52F6-4E29-BA64-0ADC22A1FB11")]
public interface IComm
{
string GetMyGroups();
}
Now define a class that implements that interface (again, replace GUIDs with your own):
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
[GuidAttribute("C5C5A1A8-9BFB-4CE5-B42C-4E6688F6840B")]
[ProgId("Test.Comm.1")]
public class Comm : IComm
{
public string GetMyGroups()
{
var comm = new CommunicatorAPI.MessengerClass();
var groups = comm.MyGroups as IMessengerGroups;
return string.Join(", ", groups.OfType<IMessengerGroup>().Select(g => g.Name).ToArray());
}
}
The Prog ID attribute on this class is what you will use to instantiate your component from ASP.
Strongly-name the assembly (Project properties -> "Signing" tab -> "Sign the assembly" -> Create a new strong name key file using the dropdown)
Now, build the assembly, and register using Regasm - if you don't wish to register in the GAC (which i'd recommend, as not GACing keeps the deployment simpler), be sure to use the -Codebase parameter (this just adds a reg entry that tells clients where to find the assembly) - e.g:
regasm ClassLibrary2.dll /codebase "S:\Testing\ClassLibrary2\ClassLibrary2\bin\Debug\ClassLibrary2.dll"
Now you should be able to instantiate the component, and call methods on it - for example (in javascript):
var a = new ActiveXObject("Test.Comm.1");
alert(a.GetMyGroups());
When it comes to deployment, the important work that Regasm and Regsvr32 do is to write various settings into the registry, so that clients can find the COM component (based on Prog ID, or COM Class ID). All you need to do is work out what COM settings are being written when you run Regasm on your local machine, and write these to the registry on the server. You can use ProcMon to monitor what gets written to the registry when Regasm is run.
Generally speaking, you can expect to see something like this written to the registry:
[HKEY_CLASSES_ROOT\Test.Comm.1]
#="ClassLibrary2.Comm"
[HKEY_CLASSES_ROOT\Test.Comm.1\CLSID]
#="{00585504-90C8-4760-A359-67CAF08FFED1}"
[HKEY_CLASSES_ROOT\Wow6432Node\CLSID\{00585504-90C8-4760-A359-67CAF08FFED1}]
#="ClassLibrary2.Comm"
[HKEY_CLASSES_ROOT\Wow6432Node\CLSID\{00585504-90C8-4760-A359-67CAF08FFED1}\Implemented Categories]
[HKEY_CLASSES_ROOT\Wow6432Node\CLSID\{00585504-90C8-4760-A359-67CAF08FFED1}\Implemented Categories\{62C8FE65-4EBB-45e7-B440-6E39B2CDBF29}]
[HKEY_CLASSES_ROOT\Wow6432Node\CLSID\{00585504-90C8-4760-A359-67CAF08FFED1}\InprocServer32]
#="mscoree.dll"
"ThreadingModel"="Both"
"Class"="ClassLibrary2.Comm"
"Assembly"="ClassLibrary2, Version=1.0.0.0, Culture=neutral, PublicKeyToken=cf55d4e60653257a"
"RuntimeVersion"="v4.0.30319"
"CodeBase"="file:///S:/Testing/ClassLibrary2/ClassLibrary2/bin/Debug/ClassLibrary2.DLL"
[HKEY_CLASSES_ROOT\Wow6432Node\CLSID\{00585504-90C8-4760-A359-67CAF08FFED1}\InprocServer32\1.0.0.0]
"Class"="ClassLibrary2.Comm"
"Assembly"="ClassLibrary2, Version=1.0.0.0, Culture=neutral, PublicKeyToken=cf55d4e60653257a"
"RuntimeVersion"="v4.0.30319"
"CodeBase"="file:///S:/Testing/ClassLibrary2/ClassLibrary2/bin/Debug/ClassLibrary2.DLL"
[HKEY_CLASSES_ROOT\Wow6432Node\CLSID\{00585504-90C8-4760-A359-67CAF08FFED1}\ProgId]
#="Test.Comm.1"
Hope this helps :)
I have a Classic ASP web site that uses a VB6 COM object. I wanted to create a new version of the COM object using .NET instead of VB6. This is how I did it (hope this helps). I include instructions for both C# and VB.NET.
[01]
Start Visual Studio 2015 (run as admin).
Create a new "Class Library" project.
Name it: "DotNetCom"
[02] C#
Add a new class, name it "HelloCOM".
Use the following code as starting template
( visit https://msdn.microsoft.com/en-us/library/c3fd4a20.aspx for more info )
using System.Runtime.InteropServices;
namespace DotNetCom
{
[Guid("EAA4976A-45C3-4BC5-BC0B-E474F4C3C83F")]
public interface HelloCOMInterface
{
[DispId(1)]
string Hello();
}
[Guid("7BD20046-DF8C-44A6-8F6B-687FAA26FA71"),
InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface HelloCOMEvents
{
}
[Guid("0D53A3E8-E51A-49C7-944E-E72A2064F938"),
ClassInterface(ClassInterfaceType.None),
ComSourceInterfaces(typeof(HelloCOMEvents))]
public class HelloCOM : HelloCOMInterface
{
public string Hello()
{
return "Hello there!";
}
}
}
[02] VB.NET
Add a new "COM class", name it "HelloCOM".
VB.NET creates the starting template.
Add the following function to the "HelloCOM" class.
Public Function Hello() As String
Return "Hello there!"
End Function
[03] C#
Open the project properties.
Go to "Application".
Click "Assembly Information...".
Check "Make assembly COM-Visible"
Go to "Build".
Select "Platform target: x86".
Check "Register COM for interop"
[03] VB.NET
Open "MyProject".
Go to "Compile".
Select "Target CPU: x86".
[04]
Build the "DotNetCom.dll".
[05]
Open a command prompt (run as admin).
Change directory to your dll.
cd DotNetComTest\DotNetComTest\TX7NGN.COM\bin\Debug
Run RegAsm /codebase.
C:\Windows\Microsoft.NET\Framework\v4.0.30319\RegAsm DotNetComTest.dll /codebase "C:\DotNetComTest\DotNetComTest\bin\Debug\DotNetComTest.dll"
[06]
Start Component Services.
Add a new COM+ application.
Name it: "DotNetCom".
Open the "DotNetCom" properties.
Go to the "Security Tab".
UNCHECK "Enforce access checks for this application".
[07]
Add a new component.
Select "DotNetComTest.tlb" (do NOT select "DotNetComTest.dll").
[08]
Use the COM object from the Classic ASP page.
<%
Dim HelloCOM
Set HelloCOM = Server.CreateObject("DotNetCom.HelloCOM")
Response.Write HelloCom.Hello
%>

How to do mocks for Web tests?

I want to write a few web tests (over WatiN/Selenium + CassiniDev web server) for my asp.net web application.
Problem I encountered is that I dont know what to do in such situations:
there is a page where user can click the button to call some third-party service. In my web test i want to create mock of this service, which will always return static value (some value in these test case and other value in other test case).
How can i do that?
Currently i use IoC/DI container Microsoft Unity. And my pages gets his dependencies in a manner described in http://msdn.microsoft.com/en-us/library/ff664622%28v=pandp.50%29.aspx.
The only solution that comes to my head is: place all dependencies in web.config for each test case and copy necessary web.config on SetUp of test. This solution completly painful!
Any ideas?
I use WatiN and Cassini-dev in my integration tests as well and have had to deal with similar issues. In my setup fixture I deploy my Asp.Net web application to a temporary folder in my test folder which allows me to play around with the configuration before starting up cassini-dev. I use Windsor for my CI which allows me to change injected components at the configuration level. You may also be able to acheive this with Unity.
If the service you are referring to is a web service you just mock out a web service using the interface you have been coding to.
Here are the steps that I take when running my integration tests:
Create a temp web directory
Publish the Asp.Net web application to the temp directory (I use MSBuild to do this)
Deploy temp database (Using MSbuild and database projects but could be done a number of ways)
Deploy temp membership database (see my blog post on how to do this in code)
Update the web.config of the deployed Asp.Net web application to point to the temp databases and change any other settings relevant for testing.
Start up the website using Cassini-Dev. I also hit the site with a http request so that I can verify the site is up before running any tests.
Run the tests.
After running the tests you should clean up.
Stop cassini-dev
Delete the temp hosting folder
Delete the temp databases. I use Sql server SMO objects that allow me to query the Sql Server which I use to delete up any old databases that have been left lying around after any previously failed test runs.
How to deploy a website using MSbuild in code
var properties = new Dictionary<string, string>
{
{"Configuration", isDebug ? "Debug" : "Release"},
{"WebProjectOutputDir", tempHostingDirectory.FullName},
{"DeployToDatabase", "true"},
{"OutDir", Path.Combine(tempHostingDirectory.FullName, "bin\\")}
};
using (var engine = new ProjectCollection(properties))
{
engine
.LoadProject(<web project path>, "4.0")
.Build(new[] {"Build", "ResolveReferences", "_CopyWebApplication"});
}
Unity configuration section usage: http://www.pnpguidance.net/Post/UnityContainerUnityConfigurationSectionAppConfigWebConfig.aspx
Generating asp.net membership database in code: http://bronumski.blogspot.com/2011/06/generating-creating-aspnet-application.html
Msbuild ProjectCollection on MSDN: http://msdn.microsoft.com/en-us/library/microsoft.build.evaluation.projectcollection.aspx
It sounds like you are trying to mock a web service.
Web services usually inherit from MarshalByRefObject, this means you can create a mock by inheriting from RealProxy to create a transparent proxy that pretends to be the webservice:
class Mock : RealProxy
{
public Mock()
: base(typeof(IStuff)) { }
public IStuff GetStuff()
{
return (IStuff)GetTransparentProxy();
}
public override IMessage Invoke(IMessage msg)
{
IMethodCallMessage message = (IMethodCallMessage)msg;
// the message object provides the MethodInfo that was called
// as well as the arguments.
// <Insert logic here>
return new ReturnMessage(new NotImplementedException("comming soon to a test near you ..."), message);
}
}
I belieave NMock2 uses RealProxy for it's mocks, so you should be able to use it to mock the web service instead.

how would I call/use Subsonic from within a WinForms app being deployed over clickonce (with Sqlite DB)

Background - I need a framework/approach to managed database updates for a .NET Winforms app being deployed on users PC's via clickonce deploy. The app uses a sqlite database.
Q1. What mechanism does Subsonic use to run such migrations on the local PC? e.g. would it be MSBuild
Q2. If it does need a tool like how can my application robustly kick off MsBuild? i.e. how can it be sure what path it is installed, what if it is not installed, should I be including the MSBuild.exe in the clickonce package so that I know it is there for sure myself?
Q3. Any other suggestions on how to use Subsonic in this specific use case?
Q4. Any comments on whether MigratorDotNet would be a better fit? (if someone has had experience with both)
Q5. Could I use subsonic's bare migration framework and just have a set of SQL files to do the upgrade/downgrade? i.e. just use the framework to check database version and which scripts to run etc?
Well, the post is a little old but maybe my answers are still of use.
Q1: SubSonic Migrations are code files that are complied and executed at runtime by subcommander (sonic.exe) which means the code files have to be on disk and must follow the naming convention 001_migration_name.cs for subcommander to know the execution order.
Q2: You don't need msbuild for migrations. The only thing you need is the sonic.exe and it's dependencies.
Q3: It is possible (and not very hard) to create your own logik to execute the migrations in your project at runtime without using subcommander.
I basically find every class that is derived from Migration and (since a class cannot start with a number) my convention is that the last 3 digits from the class name are the migration number (like the 001_migration_name.cs my classes are defined as Migration001 : Migration)
public class MigrationHelper
{
private const string providerName = "MyProviderName";
public static int CurrentVersion { get { return SubSonic.Migrations.Migrator.GetCurrentVersion(providerName); } }
private static Dictionary<int, Migration> _migrations;
public static Dictionary<int, Migration> Migrations
{
get
{
if (_migrations == null)
{
_migrations = new Dictionary<int, Migration>();
foreach (Type t in new MigrationHelper().GetType().Assembly.GetExportedTypes())
{
if (t.BaseType == typeof(SubSonic.Migration))
{
int number;
if (int.TryParse(t.Name.Substring(t.Name.Length - 3, 3), out number))
Migrations.Add(number, (Migration)Activator.CreateInstance(t));
else
throw new InvalidOperationException("Classes that inherit SubSonic Migrations have to be named MigrationXXX where x is the unique migration number");
}
}
}
return _migrations;
}
}
public static void ExecuteMigration(Migration m, Migration.MigrationDirection direction)
{
m.Migrate(providerName, direction);
}
}
In your programm you can determine the current version by MigrationHelper.CurrentVersion and then execute every single migration from current to max (if you wanne go up) or some other number. Here is how you use it.
Migration m = MigrationHelper.Migrations[15];
MigrationHelper.ExecuteMigration(m, Migration.MigrationDirection.Up);
Q4: I don't have experience with MigratorDotNet but if your app uses subsonic than the subsonic migrations are a good choise since you don't need to deploy any additional libs.
Q5: You can use subsonic migrations for that. Just do:
Execute("CREATE TABLE ...");
in the Up() or Down() method. But the advantage of using the predefined methods are (besides the fact that they work across multiple dbms' which is propable not so importent if you only use sqlite) is that you have some pre flight checks (e.g. a migration will fail if you define a field twice before the actual sql is executed)

Resources