nhibernate transaction management in asp.net WebForms - c#

I've been doing some research on transaction management for NHibernate for ASP.Net applications (Webforms). Most articles I found tend to favour the transaction-per-request approach. While I understand the session-per-request, and am totally in favour of it. However, I don't exactly understand the reasoning behind the transaction-per-request.
My applications use version-field to do concurrency checks. If a problem, such a StaleObjectException, or anything else is thrown, this is thrown once you call Transaction.Commit(). My issue is that if this is in the end of request, you cannot easily know which method actually had the problematic code, and it is extremely difficult to rollback from the issue.
For example, in a StaleObjectException, normally one needs just to re-run the method, with the updated data.
Any ideas on this, and any practices for transaction management? I tend to favour opening as much transactions as possible, based on the business logic. The issue with multiple transactions is where to actually begin/end the transaction.

The transaction-per-request paradigm makes sense when you step back and think of the underlying nature of a web application. It is a request/response system, nothing more. A user submits a request for "something", which the application translates into performing an action or a series of actions, then the application sends a response to the user to indicate its current updated state.
In this model each request for action to the application can (should arguably) be atomic. After all, from the perspective of the user, conceptually what failed when there was an error? The request failed. Upon such a failure, the application should respond in two ways:
Roll back any partial changes associated with processing the request so that the persisted data isn't left in a "partial" or "undefined" state.
Inform the user (in the response) that the request has failed in some way.
My issue is that if this is in the end of request, you cannot easily know which method actually had the problematic code, and it is extremely difficult to rollback from the issue.
Can you show an example with code? I wonder if the problem might be addressed by other elements of the application's design than the transaction structure. Perhaps the processing of requests isn't properly atomic or encapsulated.
(Comments indicate that the below may be more personal opinion and is normal behavior for NHibernate)
For example, in a StaleObjectException, normally one needs just to re-run the method, with the updated data.
While I'm certainly no expert on NHibernate, I hesitate to understand what's being said here. Generally when an exception occurs, simply "trying again" is very often not a good way to handle the exception.

Related

Invoke NServiceBus Saga as a single awaitable request-response

Consider a web application that implemented every database action except querying (i.e. add, update, remove) as a NServiceBus message, so that whenever a user calls a web API, in the back-end it will be mapped to await endpointInstance.Request method to return the response in the same HTTP request connection.
The challenge is when a message handler needs to send some other messages and wait for their response to finish its job. NServiceBus does not allow to call Request inside a message handler.
I ended up using Saga to implement message handlers that are relied on some other message handler responses. But the problem with Saga is that I can't send back the result in the same HTTP request, because Saga uses publish/subscribe pattern.
All our web APIs need to be responded in the same HTTP request (connection should be kept open until the result is received or a timeout exception occurred).
Is there any clean solution (preferably without using Saga)?
An example scenario:
user call http://test.com/purchase?itemId=5&paymentId=133
web server calls await endpointInstance.Request<PurchaseResult>(new PurchaseMessage(itemId, paymentId));
PurchaseMessage handler should call await endpointInstance.Request<AddPaymentResult>(new AddPaymentMessage(paymentId));
if the AddPaymentResult was successfull, store the purchase details in the database and return true as PurchaseResult, otherwise return false
You're trying to achieve something that we (at Particular Software) are trying to actively prevent. Let me explain.
With Remote Procedure Calls (RPC) you call another component out-of-process. That what makes the procedure call 'remote'. Where with regular programming you do everything in-process and it is blazing fast, with RPC you have the overhead of serialization, latency and more. Basically, you have to deal with the fallacies of distributed computing.
Still, people do it for various reasons. Sometimes because you want to use a WebAPI (or 'old fashioned' web service) because it offers the functionality you don't want to develop. Oldest example in the book is searching for an address by postal code. Or deducting money from someone's bank account. If you're building a CRM, you can use these remote components. These days a lot of people build distributed monoliths because they are taught at conferences that this is a good thing. In an architecture diagram, it looks really nice, but there's still temporal coupling that can provide a lot of headaches.
Some of these headaches come from the fact that you're trying to do stuff in an atomic action. Back in the days, with in-process calling of code/classes/etc this was easy and fast. Until you hit limitations, like tons of locks on a database.
A solution to this is asynchronous communication. You send some information via fire-and-forget. This solves temporal coupling. Instead of having a database that is getting dozens and dozens of requests to update data, etc. and as a result, your website is grinding to a halt, you have various options to make sure this doesn't happen. This is a really good thing, because instead of a single atomic operation, you have various smaller operations and many ways to distributed work, scale your system, etc, etc.
It also brings additional challenges, because not everyone is able to work with fire-and-forget. Some systems that were already built, try to introduce asynchronous communication via messaging (and hopefully NServiceBus). Some parts can work flawlessly with this. But others parts can't. Mainly the user-interface (UI). Because it was built to get an immediate result. So when you send a message from the UI, you expect a result!
With NServiceBus we've built a package called "Client-Side Callbacks" to make exactly this a possibility. We highly recommend our customers not to use it, except for this specific scenario that I just described. It is much better to migrate your entire UI to be able to deal with the fact that you don't receive an immediate answer, but we understand this is so much work, that not many will be able to achieve this.
However once that first message was sent and the UI received a result, there is no need to use callbacks anymore. As a result I'd like to propose this scenario:
use call http://test.com/purchase?itemId=5&paymentId=133
web server calls await endpointInstance.Request<PurchaseResult>();
PurchaseMessage handler retrieves info it needs and sends or publishes a message to (an)other component(s) and then replies back to the web server with an answer.
The next handler works with the send/published message and continues the process
Let us know if you need more information. You can always contact us by sending an email to support#particular.net

Reusing the session of the thread with NHibernate

I know several topics on the subject have been discussed, because I have been reading a lot to try to resolve my issue, but somehow they happen to not fulfill my needs (maybe for the lack of detail). Anyway, if you think some specific 'topic' might be useful, please link it.
I'm developing a desktop application with WPF (and MVVM) and I'm using NHibernate. After researching about possible ways to manage my session, I have decided to use the session-per-form approach. By this way, I think I can fully use the features of NHibernate like lazy-loading, cache and so on.
As I'm working with a database, I don't want to freeze my UI while I'm loading or saving my entities, so I thought I should use a dedicated thread (in each form, which I think simplifies the development) to handle the database interaction. The problem, though, is how I should 'reuse' the thread (supposing I have a session associated with that thread) to make my 'database calls'.
I think I couldn't use TPL because I'm not guaranteed that the two tasks would run in the same thread (it's not even guaranteed that they will be run in different threads than the invoker)
I would prefer to use session-per-form, as I have seen similar discussions that end by using session-per-conversation or something like that. But anyway, if you find that session-per-conversation would be better, please tell me (and hopefully explain why)
Threads don't provide a way to directly run more than one method, so I think I would have to 'listen' for requests, but I'm still unsure if I really have to do this and how I would 'use' the session (and save it) only inside the thread.
EDIT:
Maybe I'm having this problem because I'm confusing thread-safety with something else.
When the NHibernate documentation says that ISession instances are not thread-safe, does it means that I will (or could) get into trouble if two threads attempt to use it at the same time, right? In my case, if I use TPL, different threads could use the same session, but I wouldn't perform more than one operation in the same session at the same time. So, would I get into trouble in that situation?
If I may make a suggestion, desktop applications are poorly suited to interact with the database directly. The communication is not encrypted and it's really easy for someone with even the slightest amount of know-how to grab the database password and begin messing with records using a SQL connection and corrupt your database.
It would be better to create a web service with authentication that stands between the desktop application and the database as you could create credentials for each person and every transaction would be forcibly subjected to your various business rules.
This would also take care of your threading issue as you would be able to create HTTP connections on another thread with little to no trouble concerning session management. A cookie value is likely all that would be required and RestSharp makes this fairly trivial.

How to rollback transaction at later stage?

I have a data entry ASP.NET application. During a one complete data entry many transactions occur. I would like to keep track of all those transactions so that if the user wants to abandon the data entry, all the transaction of which I have been keeping record can be rolled back.
SQL 2008 ,Framework version is 4.0 and I am using c#.
This is always a tough lesson to learn for people that are new to web development. But here it is:
Each round trip web request is a separate, stand-alone thread of execution
That means, simply put, each time you submit a page request (click a button, navigate to a new page, even refresh a page) then it can run on a different thread than the previous one. What's more, even if you do get the same thread twice, several other web requests may have been processed by the thread in the time between your two requests.
This makes it effectively impossible to span simple transactions across more than one web request.
Here's another concept that you should keep in mind:
Transactions are intended for batch operations, not interactive operations.
What this means is that transactions are meant to be short-lived, and to encompass several operations executing sequentially (or simultaneously) in which all operations are atomic, and intended to either all complete, or all fail. Transactions are not typically designed to be long-lived (meaning waiting for a user to decide on various actions interactively).
Web apps are not desktop apps. They don't function like them. You have to change your thinking when you do web apps. And the biggest lesson to learn, each request is a stand-alone unit of execution.
Now, above, I said "simple transactions", also known as lightweight or local transactions. There's also what's known as a Distributed Transaction, and to use those requires a Distributed Transaction Coordinator. MSDTC is pretty commonly used. However, DT's perform much more slowly than LWT's. Also, they require that the infrastructure be setup to use a DTC.
It's possible to span a transaction over web requests using a DTC. This is done by "Enlisting" in a Distribute Transaction, and then somehow sharing this transaction identifier between requests. But this is a lot of work to setup, and deal with, and has a lot of error prone situations. It's not something you want to do if you have other options.
In general, you're better off adding the data to a temporary table or tables, and then when the final save is done, transfer that data to the permanent tables. Another option is to maintain some state (such as using ViewState or Session) to keep track of the changes.
One popular way of doing this is to perform operations client-side using JavaScript and then submitting all the changes to the server when you are done. This is difficult to implement if you need to navigate to different pages, however.
From your question, it appears that the transactions are complete when the user exercises the option to roll them back. In such cases, I doubt if the DBMS's transaction rollback semantics would be available. So, I would provide such semantics at the application layer as follows:
Any atomic operation that can be performed on the database should be encapsulated in a Command object. Each command will implement the undo method that would revert the action performed by its execute method.
Each transaction would contain a list of commands that were run as part of it. The transaction is persisted as is for further operations in future.
The user would be provided with a way to view these transactions that can be potentially rolled back. Upon selection of a transaction by user to roll it back, the list of commands corresponding to such a transaction are retrieved and the undo method is called on all those command objects.
HTH.
You can also store them on temporary Table and move those records to your original table 'at later stage'..
If you are just managing transactions during a single save operation, use TransactionScope. But it doesn't sound like that is the case.
If the user may wish to abandon n number of previous save operations, it suggests that an item may exist in draft form. There might be one working draft or many. Subsequently, there must be a way to promote a draft to a final version, either implicitly or explicitly. Think of how an email program saves a draft. It doesn't actually send your message, you may abandon it at any time, and you may recall it at a later time. When you send the message, you have "committed the transaction".
You might also add a user interface to rollback to a specific version.
This will be a fair amount of work, but if you are willing to save and manage multiple copies of the same item it can be accomplished.
You may save the a copy of the same data in the same schema using a status flag to indicate that it is a draft, or you might store the data in an intermediate format in separate table(s). I would prefer the first approach in that it allows the same structures to be used.

"User already logged" HttpContext or Request DB

So, im working in a huge .NET MVC 3 system. As many users could be logged in at same time. I was just writting a way of "hey there's still someone logged with this key" with HttpContext. But, is this the best practice ? is it better to Query DB ?
what i wrote:
MvcApplication.SessionsLock();
if (!force && MvcApplication.Sessions.Values.Any(p => p.ID.Equals(acesso.id_usuario.ToString(CultureInfo.InvariantCulture)) && p.Valid))
throw new BusinessException("There's another user logged with this key. Continue ?");
MvcApplication.SessionsUnlock();
our I can query my DB.. maybe cookies ? any ideas would be appreciated
Storage
The database provides a central, durable location for this information. You might use a custom data structure, or ASP.Net SQL session might meet your requirements (more below on this).
There is not a deterministic way of always knowing exactly when a user's session ended. For example, you can listen to the Session End event, but it will only fire for in-process sessions and is not guaranteed to fire at all (e.g. the OS could crash).
Regardless, if you are building a "huge system" as you state, you shouldn't design against using in-proc session as it won't scale upwards. Start thinking about SQL-based session state which is more scalable (and may give you enough information to determine roughly how many users are active).
Session Pro/Con
I want to know if session is a good practice. That piece of code
works. But i have been reading a lot of articles deprecating usage of
sessions on ASP.NET MVC Application.
As far as Session being a good or bad thing--as always--it depends on how it is used. Properly designed MVC apps can present fairly complex views without needing to preserve state. Part of this is due to strong support for AJAX (no need to reload the page) and elegant model binding (which can take a complex Request.Form and turn it into a complete model).
Conversely, there is nothing inherently wrong with putting small snippets of repeatedly-used information into session state, using it to avoid sending sensitive data to the client, using it to make a smoother user flow, etc.
Do beware of session fixation attacks in high-security scenarios. Session may not be appropriate and/or may need to be manually secured further.
One thing to be aware of is that ASP.Net places a lock on session. This can lead to very real performance issues when multiple requests are made at once. Normally, this isn't an issue, but consider a page with a dozen AJAX widgets which all requested data from a controller or endpoint that used session. These will contend with each other (firsthand experience).
A non-locking in-process ASP.NET session state store
https://stackoverflow.com/a/2327051/453277
MVC provides an easy way to mark a controller as needing only readonly access to Session, which eliminates the issue. However, any read/write activity to Session will still be serialized, so plan accordingly.
Business Considerations
From a business perspective it's not always important to know that the session has expired so much as work has ceased (do you care that they stopped using the site, or that their session timed out?) This can be reliably addressed by checking last modified timestamps on entities and warning the users. Warn, don't lock. In my opinion, you shouldn rarely/never lock records based on login/logout in a web application (too easy to get stuck in a locked status).

Architectural question

As a result of a previous post (Architecture: simple CQS) I've been thinking how I could build a simple system that is flexible enough to be extended later.
In other words: I don't see the need for a full-blown CQRS now, but I want it to be easy to evolve to it later, if needed.
So I was thinking to separate commanding from querying, but both based on the same database.
The query part would be easy: a WCF data service based on views to that it's easy to query for data. Nothing special there.
The command part is something more difficult, and here's an idea: commands are of course executed in an asynchronous way, so they don't return a result. But, my ASP.NET MVC site's controllers often need feedback from a command (for example if a registration of a member succeeded or not). So if the controller sends a command, it also generates a transaction ID (a guid) that is passed together with the command properties. The command service receives this command, puts it into a transactions table in the database with state 'processing', and is executed (using DDD principles). After execution, the transactions table is updated, so that state becomes 'completed' or 'failed', and other more detailed information like the primary key that was generated.
Meanwhile the site is using the QueryService to poll for the state of this transaction, until it receives 'completed' or 'failed', and then it can continue its work based on this result. If the transactions table is polled and the result was 'completed' or 'failed', the entry is deleted.
A side effect is that I don't need guid's as keys for my entities, which is a good thing for performance and size.
In most cases this polling mechanism is probably not needed, but is possible if needed. And the interfaces are designed with CQS in mind, so open for the future.
Do you think of any flaws in this approach? Other ideas or suggestions?
Thanks!
Lud
I think you are very close to a full CQRS system with your approach.
I have a site that I used to do something similar to what you are describing. My site, braincredits.com, is architected using CQRS, and all commands are async in nature. So, as a result, when I create an entry, there is really no feedback to the user other than the command was successfully submitted for processing (not that it processed).
But I have a user score on the site (a count of their "credits") that should change as the user submits more items. But I don't want the user to keep hitting F5 to refresh the browser. So I am doing what you are proposing -- I have an AJAX call that fires off every second or two to see if the user's credit count has changed. If it has, the new amount is brought back and the UI is updated (with a little bit of animation to catch the user's attention -- but not too flashy).
What you're talking about is eventual consistency -- that the state of the application that the user is seeing will eventually be consistent with the system data (the system of record). That concept is pretty key to CQRS, and, in my opinion, makes a lot of sense. As soon as you retrieve data in a system (whether it's a CQRS-based one or not), the data is old. But if you assume that and assume that the client will eventually be consistent, then your approach makes sense and you can also design your UI to account for that AND take advantage of that.
As far as suggestions, I would watch how much polling you do and how much data you're sending up and back. Do go overboard with polling, which is sounds like you're not. But target what should be updated on a regular basis on your site and I think you'll be good.
The WCF Data Service layer for the query side is a good idea - just make sure it's only read-enabled (which I'm sure you've done).
Other than that, it sounds like you're off to a good start.
I hope this helps. Good luck!

Categories