Castle Automatic Transaction Management Facility persist issues - nhibernate

Regarding the Castle Automatic Transaction Management Facility; I'm having some difficulties getting operations to actually save to the database without flushing the session.
I'm using the following components
* NHibernate.dll v3.1.0.4000
* Castle.Core.dll v2.5.2.0
* Castle.Windsor.dll v2.5.3.0
* Castle.Facilities.NHibernateIntegration.dll v1.1.0.0
* Castle.Services.Transaction.dll v2.5.0.0
* Castle.Facilities.AutoTx.dll v2.5.1.0
I have followed the Castle documentation very closely and have not been able to resolve my issue.
My (web-)application follows the MVP pattern. The key parts of the (transactional) presenter-service are shown below:
<Transactional()> _
Public Class CampusEditPresenter
Inherits BasePresenter(Of ICampusEditView)
Public Sub New(ByVal view As ICampusEditView)
MyBase.New(view)
End Sub
...
<Transaction(TransactionMode.Requires)> _
Public Overridable Sub Save() Implements ICampusEditPresenter.Save
' Simplified
Using session As ISession = _sessionManager.OpenSession()
Dim campus As New Campus()
campus.Code = _view.Code
campus.ShortDescription = _view.ShortDescription
campus.LongDescription = _view.LongDescription
campus.StartDate = _view.StartDate
campus.EndDate = _view.EndDate
session.Save(campus)
End Using
End Sub
End Class
This presenter-service is registered in an installer:
container.Register( _
Component.For(Of CampusEditPresenter) _
.Interceptors(Of DebugLoggingInterceptor) _
.LifeStyle.Transient)
and resolved by the view (in the base):
Public Class BasePage(Of TPresenter)
Inherits Page
Protected _presenter As TPresenter
...
Protected Sub Page_Init(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Init
_presenter = _container.Resolve(Of TPresenter)(New With {Key .view = Me})
End Sub
...
End Class
Public Class CampusEdit
Inherits BasePage(Of CampusEditPresenter)
Implements ICampusEditView
...
Protected Sub btnSave_Click(ByVal sender As Object, ByVal e As EventArgs) Handles btnSave.Click
_presenter.Save()
End Sub
...
End Class
I have registered the NHibernate and Transaction facilities in an XML configuration file as follows:
<facility id="transaction" type="Castle.Facilities.AutoTx.TransactionFacility, Castle.Facilities.AutoTx" />
<facility id="nhibernate" type="Castle.Facilities.NHibernateIntegration.NHibernateFacility, Castle.Facilities.NHibernateIntegration" isWeb="true" configurationBuilder="[removed].AutoConfigurationBuilder, [removed]">
<factory id="nhibernate.factory">
<settings>
<item key="connection.driver_class">NHibernate.Driver.OracleClientDriver, NHibernate</item>
<item key="connection.connection_string">[removed]</item>
<item key="show_sql">false</item>
<item key="dialect">NHibernate.Dialect.Oracle10gDialect, NHibernate</item>
<item key="query.substitutions">true 1, false 0, yes 'Y', no 'N'</item>
<item key="proxyfactory.factory_class">NHibernate.ByteCode.Castle.ProxyFactoryFactory, NHibernate.ByteCode.Castle</item>
<item key="current_session_context_class">web</item>
<item key="hbm2ddl.keywords">auto-quote</item>
</settings>
</factory>
</facility>
and I have registered the SessionWebModule Http module in my Web.config:
<httpModules>
<add name="NHibernateSessionWebModule" type="Castle.Facilities.NHibernateIntegration.Components.Web.SessionWebModule, Castle.Facilities.NHibernateIntegration"/>
...
</httpModules>
Any ideas as to why this may not be working?
I can get everything working when I a) instansiate my own transactions from the ISession instance and maually commit these transactions, or if I b) use the Automatic Transaction Management AOP-mechanism AND manuall flush the session instance (though I shouldn't have to manually do this).
I would have also thought that SessionWebModule IHttpModule (which follows the open-session-per-request pattern) would cause my entities to be persisted, but this doesnt seem to be happening...

So I worked out the TransactionInterceptor was not getting registerd on my components.
After downloading the Castle.Facilities.AutomaticTransactionManagement source from github and stepping through, I found my issue and managed to resolve it.
Basically the TransactionFacility adds a contributor, TransactionComponentInspector, to the ComponentModelBuilder, which allows for some additional configuration contribution whilst building the component. In the case of the TransactionComponentInspector, it looks for a "Transactional" class attribute on the component and if it exists it will register a TransactionInterceptor on the component. However, my components were never getting contributed to by the TransactionComponentInspector.
To configure/register my components on the container, I use Installers. I configure the container itself using XML, which references these installers as well as any facilities (e.g. NHibernate-integration/logging etc.). Anyways, I believe it may have been some kind of ordering issue whereby my components might have been getting registered before the transaction facility. As such components registered before the TransactionFacility were not getting contributed-to by the TransactionComponentInspector and were therefore not getting a TransactionInterceptor registered on the component. Once I realised this I manually configured the container (with the correct order of things) and everything seemed to work!!!
Now I've got to try and work out how to do this in my XML configuration. If I can't, I guess I'll dump this and go for fluent configuration of the container (e.g. in the global HttpApplication).
[edit] see below:
_container = New WindsorContainer()
' TransactionFacility must be registered before components.
_container.AddFacility(Of TransactionFacility)()
_container.Install(Configuration.FromXmlFile("Configs\services.xml"))

I was experiencing very similar behavior. It turned out that I was creating a Logging Aspect Interceptor. I had created a Default Interceptor Selector so that I could apply logging where needed. In doing this, I was messing up the TransactionalInterceptor. Once I removed the Default Interceptor Selector, the Transactions started working.

Try SwampyFox's suggestion, then also try the nuget of 3.0.x of Tx, AutoTx and NHibFac, if that doesn't solve your problems. New development (if it's a bug) is going into those. Tell is the result of trying Foxy's suggestion.

Related

Visual Studio is not letting me add CefSharpBrowserControl to a form via the designer

So I decided to try out the CefSharp extension, and what's the first thing I encounter? An error that doesn't let me use the add-on.
This is ridiculously frustrating because I've done every single thing even the administrator or creator has said to do on any forum I've been on. I tried to just compile the source code on the CEFSharp's GitHub, but that didn't work.
If I'm brutally honest, I think that they should just provide a pre-compiled .dll file or group of .dll files that you can just add to the references, instead of just expecting you to do it yourself. It's just a pain, CEFSharp.
I've tried putting the Configuration to x64 AND Any CPU. I've tried making references to several different dlls associated to CEFSharp. I've tried to add the browser element programmatically, and that's worked, but I can't do anything with it (such as execute code when the webpage is done loading). So far none of these solutions have worked at all.
Imports CefSharp
Imports CefSharp.WinForms
Public Class Browser
Dim browser As New _
CefSharp.WinForms.ChromiumWebBrowser("https://google.com/")
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles _
MyBase.Load
Me.Controls.Add(browser)
browser.Parent = Panel1
browser.Dock = DockStyle.Fill
End Sub
End Class
Any time I want to add the browser control to my form via the designer toolbox, it won't let me. It keeps showing this error box that says "Failed to load CefSharpBrowser, deleting from the toolbox." Or something along those lines. It's supposed to just be able to drop into the designer, but it's obviously not.
There are similar discussions on CefSharp's google group: Adding CefSharp control to the toolbox and The name "WebView" does not exist in the namespace.
They say that Visual Studio has some limitations when using a mixed mode (C++/CLR) assembly. There is no Visual Studio designer support out of the box in CefSharp. There is some hack about how to do it, but I do not think it worth it to even spend time on it. Most people just accept the fact and move on.
We successfully use CefSharp for one of our projects and we add ChromiumWebBrowser control to a form programmatically, very similar to how you did it in your sample.
I've tried to add the browser element programmatically, and that's
worked, but I can't do anything with it (such as execute code when the
webpage is done loading). So far none of these solutions have worked
at all.
There is a LoadingStateChanged event which you can use to monitor the status of a web browser control. We use it to show progress indication until our web page is fully loaded. Here is how we do it:
private System.Windows.Forms.PictureBox picProgress;
bool loaded = false;
ChromiumWebBrowser browse;
public Main()
{
var uiUrl = "some url or local html file";
browse = new ChromiumWebBrowser(uiUrl);
browse.Dock = DockStyle.Fill;
Controls.Add(browse);
browse.LoadingStateChanged += Browse_LoadingStateChanged;
}
private void Browse_LoadingStateChanged(object sender, LoadingStateChangedEventArgs e)
{
if (!e.IsLoading)
{
picProgress.BeginInvoke((Action)(() => {
loaded = true;
picProgress.Visible = false;
browse.Visible = true;
}));
}
else
{
browse.BeginInvoke((Action)(() => {
loaded = false;
browse.Visible = false;
}));
}
}
Sorry, it is in C#, but I think you can easily adapt it for VB.net.

What are DShellFolderViewEvents and DShellFolderViewEvents_Event?

The names make it sound like some sort of event handler.
Both were identified as an interface from Shell32 using the code below:
I can't find either of these in the MSDN libraries. Google returned some pages with code where they appeared, but I didn't see anything that really described the interface.
Public Sub ListTypes()
Dim NS As String = "Shell32"
For Each t As Type In Assembly.GetExecutingAssembly().GetTypes()
If (t.IsClass Or t.IsInterface) And t.Namespace = NS Then
Debug.Print(t.Name)
End If
Next
End Sub
Based on the definition in ShlDisp.h it appears to simply be a thin wrapper around IDispatch with a different GUID.
MIDL_INTERFACE("62112AA2-EBE4-11cf-A5FB-0020AFE7292D")
DShellFolderViewEvents : public IDispatch
{
};
It seems to be used in obtaining event notification from the shell - Raymond Chen's blog has some example code.

Embedded RavenDB Logging in debug output

I am currently investigating in RavenDB and set up this simple test
<TestFixtureSetUp()>
Public Sub Setup()
_embeddableDocumentStore = New EmbeddableDocumentStore With {.DataDirectory = "localdatabase"}
_embeddableDocumentStore.Initialize()
End Sub
<Test> Public Sub CreateDB()
Dim session = _embeddableDocumentStore.OpenSession()
Dim results = session.Query(Of testclass)().ToList()
For Each testclass In results
session.Delete(testclass)
Next
session.SaveChanges()
session.Store(New testclass With {.Id = 4, .Name = "177mdffarsdfdffds6t2in611"})
session.Store(New testclass With {.Id = 2, .Name = "17fd7martrsdfdffds6t2in611"})
session.Store(New testclass With {.Id = 3, .Name = "re177marsdfdfffdfds6t2in611"})
session.SaveChanges()
results = session.Query(Of testclass)().ToList()
For Each testclass In results
session.Delete(testclass)
Next
session.SaveChanges()
results = session.Query(Of testclass)().ToList()
Assert.AreEqual(0, results.Count())
End Sub
<TestFixtureTearDown()>
Public Sub TearDown()
_embeddableDocumentStore.Dispose()
_embeddableDocumentStore = Nothing
End Sub
But can I get the embedded RavenDB database to write debugging info to the visual studio Debug Output? I have tried adding a nlog.config in the bin\debug folder with this content, but when I debug I get no info about queries in the output... What am I doing wrong?
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.netfx35.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<targets>
<target xsi:type="Console" Name="Console" />
</targets>
<rules>
<logger name="Raven.Client.*" writeTo="Console"/>
</rules>
</nlog>
Forgive my poor VB translation, I usually develop in C#
Specifically regarding logging in unit tests - I find it much easier to use the abstraction layer and forget about NLog.
Imports Raven.Abstractions.Logging
...
<TestFixtureSetUp>
Public Sub Setup()
LogManager.RegisterTarget(Of DebugTarget)()
End Sub
Class DebugTarget
Inherits Target
Public Overrides Sub Write(logEvent As LogEventInfo)
' whatever you want to do
If logEvent.Level >= LogLevel.Info Then
Debug.WriteLine("{0} - {1} - {2}", _
logEvent.TimeStamp.ToLocalTime().ToString("hh:mm:ss.fff"), _
logEvent.Level, _
logEvent.FormattedMessage)
End If
End Sub
End Class
In regards to your test as a whole - there are a lot of problems:
Unit tests should not write to disk. Not only is there a performance cost, but multiple tests could step on each other. Run in memory instead.
Don't use test setup/teardown for the document store. Each test should get its own in-memory document store. Put it in a Using statement block to dispose on test completion.
Don't try to manage your own cleanup by deleting records. Just start clean each time.
Sessions should always go in a Using statement block. Whether testing or in real code.
When testing, it's good practice to create separate sessions for the Arrange/Act portion of your test and the Assert portion. Otherwise, you aren't necessarily checking what's in the database - you might just be checking what's tracked in the session.
Unit tests should always use the WaitForNonStaleResults customization on any queries. Otherwise you may be testing stale results. Read here for more information about stale results.
Here is a complete example of your test written properly.

Context issue in IHttpHandler

Sorry, this can be a basic question for advanced VB.NET programmers but I am a beginner in VB.NET so I need your advice.
I have a web application and the login is required for some specific pages. To check if the user is logged in, the old programmer used this technique:
Dim sv As New WL.SessionVariables(Me.Context)
If Not (sv.IsLoggedIn) Then
Response.Redirect(WL.SiteMap.GetLoginURL())
End If
Well, I have to use this Logged In checking in a handler done by me and I tried this:
Public Class CustomHandler
Implements System.Web.IHttpHandler, IReadOnlySessionState
Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
Dim sv As New WL.SessionVariables(context)
If Not (sv.IsLoggedIn) Then
context.Response.Write("No access unless you're the CEO!!!" & sv.IsLoggedIn)
ElseIf sv.IsLoggedIn Then
DownloadFile(context)
Else
End If
End Sub
//other code
End Class
Well, the "is logged in" checking is always false (even after I login) and I think it's an issue with the context. So all the other pages works fine with logging checking but this handler have this specific issue.
Can you guys give a helping hand?
UPDATE:
The logged in is done trough this method:
Public Sub SetCreditialCookie(ByVal accountID As Integer)
Me.AccountID = accountID
m_context.Session.Item("loggedInAccount") = accountID
m_context.Response.Cookies.Add(New System.Web.HttpCookie("account_id", CStr(m_context.Session.Item("account_id"))))
m_context.Response.Cookies("account_id").Expires = DateTime.Now.AddDays(5)
End Sub
and to check it it's logged in, this method is called:
Public Function IsLoggedIn() As Boolean
If Not m_context.Session.Item("loggedInAccount") Is Nothing And Me.AccountID = m_context.Session.Item("loggedInAccount") Then
Return True
Else
Return False
End If
End Function
UPDATE 2:
- debugging the code shown that there were multiple kind of logins and I was checking the wrong one with the session.
Due to the use of IReadOnlySessionState, is it possible that the SessionVariables class attempts in some way to modify the Session, which in turn causes an error (possibly handled and not visible to you).
If this is the case it could mean that the IsLoggedIn property is not correctly initialised, or does not function as expected?
Do you have access to the code for the class. If so, try debugging it to see what is happening.

How can I write to my own app.config using a strongly typed object?

The following code has two flaws, I can't figure out if they are bugs or by design. From what I have seen it should be possible to write back to the app.config file using the Configuration.Save and according to http://www.codeproject.com/KB/cs/SystemConfiguration.aspx the code should work.
The bugs are shown in the source below and appear when you try to set the property or save the config back out.
Imports System.Configuration
Public Class ConfigTest
Inherits ConfigurationSection
<ConfigurationProperty("JunkProperty", IsRequired:=True)> _
Public Property JunkProperty() As String
Get
Return CStr(Me("JunkProperty"))
End Get
Set(ByVal value As String)
' *** Bug 1, exception ConfigurationErrorsException with message "The configuration is read only." thrown on the following line.
Me("JunkProperty") = value
End Set
End Property
Public Sub Save()
Dim ConfigManager As Configuration = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None)
' The add / remove is according to http://www.codeproject.com/KB/cs/SystemConfiguration.aspx
ConfigManager.Sections.Remove("ConfigTest")
' *** Bug 2, exception InvalidOperationException thrown with message "Cannot add a ConfigurationSection that already belongs to the Configuration."
ConfigManager.Sections.Add("ConfigTest", Me)
ConfigManager.Save(ConfigurationSaveMode.Full, True)
End Sub
Public Shared Sub Main()
Dim AppConfig As ConfigTest = TryCast(ConfigurationManager.GetSection("ConfigTest"), ConfigTest)
AppConfig.JunkProperty = "Some test data"
AppConfig.Save()
End Sub
' App.Config should be:
' <?xml version="1.0" encoding="utf-8" ?>
'<configuration>
' <configSections>
' <section name="ConfigTest" type="ConsoleApp.ConfigTest, ConsoleApp" />
' </configSections>
' <ConfigTest JunkProperty="" />
'</configuration>
End Class
I'd like to do it this way so that on the first run of the app I check for the properties and then tell the user to run as admin if they need to be set, where the UI would help them with the settings. I've already 'run as admin' to no effect.
Your code doesn't really make any sense. I took your example code and turned it into a simple example that works. Please note this is not best practise code, merely an example to aid you on your journey of learning the configuration API.
Public Class ConfigTest
Inherits ConfigurationSection
<ConfigurationProperty("JunkProperty", IsRequired:=True)> _
Public Property JunkProperty() As String
Get
Return CStr(Me("JunkProperty"))
End Get
Set(ByVal value As String)
' *** Bug 1, exception ConfigurationErrorsException with message "The configuration is read only." thrown on the following line.
Me("JunkProperty") = value
End Set
End Property
Public Overrides Function IsReadOnly() As Boolean
Return False
End Function
Public Shared Sub Main()
Dim config As Configuration = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None)
Dim AppConfig As ConfigTest = config.GetSection("ConfigTest")
AppConfig.JunkProperty = "Some test data"
config.Save()
End Sub
End Class
This code will open the config file, modify the attribute JunkProperty and persist it back it the executable's configuration file. Hopefully this will get you started- it looks like you need to read about the configuration API a bit more.
I've used the API to create configuration sections for large scale enterprise apps, with several 1000 of lines of custom hierarchical config (my config was readonly though). The configuration API is very powerful once you've learnt it. One way I found out more about its capabilities was to use Reflector to see how the .NET framework uses the API internally.
Maybe you don't know Portuguese or c# but this is you want http://www.linhadecodigo.com.br/Artigo.aspx?id=1613
using BuildProvider from asp.net
After loading a configuration it is readonly by default, principally because you have not overriden the IsReadOnly property. Try to override it.
¿Is there something that prevents you from using a setting?
Looks like it is not possible by design. App.config is normally protected as it resides along with the app in the Program Files directory so must be amended at installation time by the installer.
Pity really, I'd like the app to have settings that an admin can set.
Sorry if I didn't understand your case, but yes, you can change App.config at runtime.
Actually, you will need to change YourApp.exe.config, because once your app is compiled, App.config contents are copied into YourApp.exe.config and your application never looks back at App.config.
So here's what I do (C# code - sorry, I still haven't learnt VB.Net)
public void UpdateAppSettings(string key, string value)
{
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile);
foreach (XmlElement item in xmlDoc.DocumentElement)
{
foreach (XmlNode node in item.ChildNodes)
{
if (node.Name == key)
{
node.Attributes[0].Value = value;
break;
}
}
}
using (StreamWriter sw = new StreamWriter(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile))
{
xmlDoc.Save(sw);
}