i have a method with the following signature that belongs to a class.
public virtual IAsyncResult DoSomething(CustomOptions options);
I am trying to figure out how exactly do i call the callback.I cannot find anywhere the event on which to give a callback method.
This is copied pretty much from MSDN:
// Initiate the asychronous call.
IAsyncResult result = caller.BeginInvoke(3000,
out threadId, null, null);
Thread.Sleep(0);
Console.WriteLine("Main thread {0} does some work.",
Thread.CurrentThread.ManagedThreadId);
// Wait for the WaitHandle to become signaled.
result.AsyncWaitHandle.WaitOne();
// Perform additional processing here.
// Call EndInvoke to retrieve the results.
string returnValue = caller.EndInvoke(out threadId, result);
If the method is your own, you might want to try returning a Task, which will have a ContinueWith method, that takes a block of code (Another Task) as a callback, which will run once the Task has completed.
To understand how to use IAsyncResult, you should understand where it would be use. It's normally used for asynchronous call. The most common usage is delegate asynchronous call. In that case, IAsyncResult is a receipt, it is used as an "Infomation carrier", and provides a synchronization object in order to abort the thread when asynchronous operation completes.
Usually you don't need to create an IAsyncResult. IAsyncResult is just a way to implement receipt function. You may not make it so complicated. Just transmit a simple struct to carry infomations you need.
like:
/// <summary>
/// This is a simplified IAsyncResult
/// </summary>
public class Receipt
{
/// <summary>
/// Name
/// </summary>
public String Name
{
get;
set;
}
/// <summary>
/// Age
/// </summary>
public Byte Age
{
get;
set;
}
public String OperationResultText
{
get;
set;
}
}
public class Test
{
public delegate void Async_OperationCallbackHandler(Receipt r);
public void MainEntry()
{
Thread tmpThread = new Thread(()=>
{
Async_Operation("ASDF", 20, Async_Operation_Callback);
});
tmpThread.Start();
}
public void Async_Operation(String name, Byte age, Async_OperationCallbackHandler callback)
{
//Do something with "name" and "age" and get result...
String result = "OK...";
Receipt r = new Receipt()
{
Age = age,
Name = name,
OperationResultText = result
};
callback(r);
}
internal void Async_Operation_Callback(Receipt r)
{
Console.WriteLine("Name = " + r.Name + ", Age = " + r.Age + ", Operation result: " + r.OperationResultText);
}
}
Of course, I did not consider synchronization. But .NET Framework has taken into it. So determine the contents of receipt according to your needs, not need to use IAsyncResult.
See:
Calling Synchronous Methods Asynchronously
IAsyncResult Interface
Related
I am getting the below error. Axon version 3.3.3
org.axonframework.eventsourcing.IncompatibleAggregateException:
Aggregate identifier must be non-null after applying an event. Make
sure the aggregate identifier is initialized at the latest when
handling the creation event.
I have created a UserAggregate. It contains 2 events:
UserCreated
UpdateUserEvent
I am able to generate the first (UserCreated) event and it was saved in the event store with sequence 0, But while generating the second event I got the above-mentioned error.
Any suggestions on this?
UserAggregate.java
#Aggregate
public class UserAggregate {
#AggregateIdentifier
private String id;
private String email;
private String password;
public UserAggregate(String id, String email, String password) {
super();
this.id = id;
this.email = email;
this.password = password;
}
#CommandHandler
public UserAggregate(CreateUser cmd) {
AggregateLifecycle.apply(new UserCreated(cmd.getId(), cmd.getEmail(), cmd.getPassword()));
}
#CommandHandler
public void handle(UpdateUserCmd cmd) {
AggregateLifecycle.apply(new UpdateUserEvent(cmd.getId(), cmd.getEmail(),""));
}
#EventSourcingHandler
public void userCreated(UserCreated event) {
System.out.println("new User: email " + event.getEmail() +" Password: "+ event.getPassword());
setId(event.getId());
}
#EventSourcingHandler
public void updateUserEvent(UpdateUserEvent event) {
System.out.println("new User: email " + event.getEmail());
setId(event.getId());
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public UserAggregate() {
}
}
I am still getting to know Axon but here's how I managed to resolve the issue. Basically what the error is saying is that, when the UserAggregate is being instantiated the aggregate identifier (aka Primary Key) must not be null and must have a value.
There sequence of the life-cycle is that
It calls a no args constructor
It calls the constructor with your initial command, in your case. At this point, your aggregate identifier is still null and we will assign a value in the next step
It then calls a EventSourcingHandler that handles the event your applied from the previous step
Based on the steps above here's what you need to do:
Create a no args constructor
protected UserAggregate() {
}
Create a constructor which handles your first command:
#CommandHandler
public UserAggregate(CreateUser cmd) {
AggregateLifecycle.apply(
new UserCreated(cmd.getId(),cmd.getEmail(),cmd.getPassword()));
}
Finally add an event sourcing handler to handle the UserCreated event
#EventSourcingHandler
public void on(UserCreated userCreated) {
// this is where we instantiate the aggregate identifier
this.id = userCreated.getId();
//assign values to other fields
this.email = userCreated.getEmail();
this.password = userCreated.getPassword();
}
And here's the complete example:
#Aggregate
public class UserAggregate {
#AggregateIdentifier
private String id;
private String password;
private String email;
protected UserAggregate() {
}
#CommandHandler
public UserAggregate(CreateUser cmd) {
AggregateLifecycle.apply(
new UserCreated(cmd.getId(),cmd.getEmail(),cmd.getPassword()));
}
#EventSourcingHandler
public void on(UserCreated userCreated) {
// this is where we instantiate the aggregate identifier
this.id = userCreated.getId();
//assign values to other fields
this.email = userCreated.getEmail();
this.password = userCreated.getPassword();
}
}
When you are following the Event Sourcing paradigm for your Aggregates, I'd typically suggest two types of constructors to be present in the code:
A default no-arg constructor with no settings in it.
One (or more) constructor(s) which handles the 'Aggregate creation command'
In your example I see a third constructor to set id, email and password.
My guess is that this constructor might currently obstruct the EventSourcedAggregate implementation for correct validation.
The exception you are receiving can only occur if the #AggregateIdentifier annotated field is not set after the constructor command handler (in your case UserAggregate(CreateUser) has ended it's Unit of Work.
Thus, seeing your code, my only hunch is this "wild, unused" constructor which might obstruct things.
Lastly, I need to recommend you to use a more recent version of Axon.
3.3.3 is already quite far away from the current release, being 4.2.
Additionally, no active development is taking place on Axon 3.x versions.
It is thus wise to upgrade the version, which I assume shouldn't be a big deal as you are still defining your Command Model.
Update
I've just closed the Framework issue you've opened up. Axon provides entirely different means to tie in to the Message dispatching and handling, giving you cleaner intercept points than (Spring) AOP.
If you following the suggested guidelines to use a MessageDispatchInterceptor/MessageHandlerInterceptor or the more fine grained option with HandlerEnhancer, you can achieve these cross-cutting concerns you are looking for.
As far as logging goes, the framework even provides a LoggingInterceptor to do exactly what you need. No AOP needed.
Hope this helps you out Narasimha.
Thank you #Steven for the response.
I am able to reproduce this issue with Axon 4.2(latest) version also.
After removing the below AOP code in my project, The issue solved automatically.
Looks like Axon is missing compatible with the AOP feature.
AOP Code:
#Around("execution(* com.ms.axonspringboot..*(..))")
public Object methodInvoke(ProceedingJoinPoint jointPoint) throws Throwable {
LOGGER.debug(jointPoint.getSignature() + "::: Enters");
Object obj = jointPoint.proceed();
LOGGER.debug(jointPoint.getSignature() + "::: Exits");
return obj;
}
Axon 4.2 version error logs
2019-10-07 12:52:41.689 WARN 31736 --- [ault-executor-0] o.a.c.gateway.DefaultCommandGateway : Command 'com.ms.axonspringboot.commands.UpdateUserCmd' resulted in org.axonframework.commandhandling.CommandExecutionException(Aggregate identifier must be non-null after applying an event. Make sure the aggregate identifier is initialized at the latest when handling the creation event.)
2019-10-07 12:52:41.710 ERROR 31736 --- [nio-7070-exec-3] o.a.c.c.C.[.[.[.[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] threw exception
org.axonframework.axonserver.connector.command.AxonServerRemoteCommandHandlingException: An exception was thrown by the remote message handling component: Aggregate identifier must be non-null after applying an event. Make sure the aggregate identifier is initialized at the latest when handling the creation event.
at org.axonframework.axonserver.connector.ErrorCode.lambda$static$8(ErrorCode.java:84) ~[axon-server-connector-4.2.jar:4.2]
at org.axonframework.axonserver.connector.ErrorCode.convert(ErrorCode.java:180) ~[axon-server-connector-4.2.jar:4.2]
I'm making a small game in LibGDX. I'm saving the player's username locally as well as on a server. The problem is that the application is not waiting for the result of the call so the online database's ID is not saved locally. Here's the overall flow of the code:
//Create a new user object
User user = new User(name);
//Store the user in the online database
NetworkService networkService = new NetworkService();
String id = networkService.saveUser(user);
//Set the newly generated dbase ID on the local object
user.setId(id);
//Store the user locally
game.getUserService().persist(user);
in this code, the id variable is not getting set because the saveUser function is returning immediately. How can I make the application wait for the result of the network request so I can work with results from the server communication?
This is the code for saveUser:
public String saveUser(User user) {
Map<String, String> parameters = new HashMap<String, String>();
parameters.put("action", "save_user");
parameters.put("json", user.toJSON());
HttpRequest httpGet = new HttpRequest(HttpMethods.POST);
httpGet.setUrl("http://localhost:8080/provisioner");
httpGet.setContent(HttpParametersUtils.convertHttpParameters(parameters));
WerewolfsResponseListener responseListener = new WerewolfsResponseListener();
Gdx.net.sendHttpRequest (httpGet, responseListener);
return responseListener.getLastResponse();
}
This is the WerewolfsResponseListener class:
class WerewolfsResponseListener implements HttpResponseListener {
private String lastResponse = "";
public void handleHttpResponse(HttpResponse httpResponse) {
System.out.println(httpResponse.getResultAsString());
this.lastResponse = httpResponse.getResultAsString();
}
public void failed(Throwable t) {
System.out.println("Saving user failed: "+t.getMessage());
this.lastResponse = null;
}
public String getLastResponse() {
return lastResponse;
}
}
The asynchrony you are seeing is from Gdx.net.sendHttpRequest. The methods on the second parameter (your WerewolfsResponseListener) will be invoked whenever the request comes back. The success/failure methods will not be invoked "inline".
There are two basic approaches for dealing with callbacks structured like this: "polling" or "events".
With polling, your main game loop could "check" the responseListener to see if its succeeded or failed. (You would need to modify your current listener a bit to disambiguate the success case and the empty string.) Once you see a valid response, you can then do the user.setId() and such.
With "events" then you can just put the user.setId() call inside the responseListener callback, so it will be executed whenever the network responds. This is a bit more of a natural fit to the Libgdx net API. (It does mean your response listener will need a reference to the user object.)
It is not possible to "wait" inline for the network call to return. The Libgdx network API (correctly) assumes you do not want to block indefinitely in your render thread, so its not structured for that (the listener will be queued up as a Runnable, so the earliest it can run is on the next render call).
I would not recommend this to any human being, but if you need to test something in a quick and dirty fashion and absolutely must block, this will work. There's no timeout, so again, be prepared for absolute filth:
long wait = 10;
while(!listener.isDone())
{
Gdx.app.log("Net", "Waiting for response");
try
{
Thread.sleep(wait *= 2);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
public static class BlockingResponseListener implements HttpResponseListener
{
private String data;
private boolean done = false;
private boolean succeeded = false;
#Override
public void handleHttpResponse(HttpResponse httpResponse)
{
Gdx.app.log("Net", "response code was "+httpResponse.getStatus().getStatusCode());
data = httpResponse.getResultAsString();
succeeded = true;
done = true;
}
#Override
public void failed(Throwable t)
{
done = true;
succeeded = false;
Gdx.app.log("Net", "Failed due to exception ["+t.getMessage()+"]");
}
public boolean succeeded()
{
return succeeded;
}
public boolean isDone()
{
return done;
}
public String getData()
{
return data;
}
}
I have an existing multi-tenant ASP.NET application where all users authenticate against a single SQL Server database. This database also contains several other settings type data that is used within the application. Each client after authentication, utilizes their own SQL Server database for data storage, for isolation purposes. Essentially all of the client database are identical and reside on the same server, but reside on one or more servers as well.
The application is currently written in asp.net 2.5 framework and utilizes the Microsoft Practices Enterprise Library for DAL, and we are looking to migrate to 4.0 and implement NHibernate to replace the MPEL.
I have implemented a solution already using NHibernate and the 4.0 framework, so I am familiar with the concepts. I found the resources for my current session manager here as a matter of fact. But that application only had a single database, so not much too it. The implementation is essentially what you see here:
http://www.lostechies.com/blogs/nelson_montalvo/archive/2007/03/30/simple-nhibernate-example-part-4-session-management.aspx
The other solutions that I have seen suggest multiple config entries and/or files to manage this, but that is not desirable, since we may add new clients frequently and all of the connection information is already maintained in the authentication database.
Does anyone have any suggestions on how I might be able to pass in the client's connection string to a session manager?
The following is my current session manager class, which is based on the article mentioned above.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Remoting.Messaging;
using System.Web;
using NHibernate;
using NHibernate.Cfg;
using NHibernate.Cache;
using singlepoint.timeclock.domain;
namespace singlepoint.timeclock.repositories
{
/// <summary>
/// Handles creation and management of sessions and transactions. It is a singleton because
/// building the initial session factory is very expensive. Inspiration for this class came
/// from Chapter 8 of Hibernate in Action by Bauer and King. Although it is a sealed singleton
/// you can use TypeMock (http://www.typemock.com) for more flexible testing.
/// </summary>
public sealed class nHibernateSessionManager
{
private ISessionFactory idadSessionFactory;
private ISessionFactory clientSessionFactory;
private string _client;
#region Thread-safe, lazy Singleton
// lazy initialisation, therefore initialised to null
private static nHibernateSessionManager instance = null;
/// <summary>
/// This is a thread-safe, lazy singleton. See http://www.yoda.arachsys.com/csharp/singleton.html
/// for more details about its implementation.
/// </summary>
public static nHibernateSessionManager Instance
{
get { return GetInstance(); }
}
public static nHibernateSessionManager GetInstance()
{
// lazy init.
if (instance == null)
instance = new nHibernateSessionManager();
return instance;
} // GetInstance
/// <summary>
/// Initializes the NHibernate session factory upon instantiation.
/// </summary>
private nHibernateSessionManager()
{
InitSessionFactory();
}
/// <summary>
/// Initializes the NHibernate session factory upon instantiation.
/// </summary>
private nHibernateSessionManager(string client)
{
InitSessionFactory();
InitClientSessionFactory(client);
}
/// <summary>
/// Assists with ensuring thread-safe, lazy singleton
/// </summary>
private class Nested
{
static Nested()
{
}
internal static readonly nHibernateSessionManager nHibernatenHibernateSessionManager = new nHibernateSessionManager();
}
#endregion
private void InitSessionFactory()
{
var configuration = new Configuration();
configuration.Configure(System.Configuration.ConfigurationManager.AppSettings["IDAD_HBM"]);
configuration.AddAssembly(typeof(enterprise).Assembly);
idadSessionFactory = configuration.BuildSessionFactory();
}
private void InitClientSessionFactory(string client)
{
var configuration = new Configuration();
configuration.Configure(System.Configuration.ConfigurationManager.AppSettings["Client_IDAD_HBM"]);
configuration.SetProperty("connection.connection_string", client);
configuration.AddAssembly(typeof(enterprise).Assembly);
clientSessionFactory = configuration.BuildSessionFactory();
}
/// <summary>
/// Allows you to register an interceptor on a new session. This may not be called if there is already
/// an open session attached to the HttpContext. If you have an interceptor to be used, modify
/// the HttpModule to call this before calling BeginTransaction().
/// </summary>
public void RegisterInterceptor(IInterceptor interceptor)
{
ISession session = ThreadSession;
if (session != null && session.IsOpen)
{
throw new CacheException("You cannot register an interceptor once a session has already been opened");
}
GetSession(interceptor);
}
public ISession GetSession()
{
return GetSession(null);
}
/// <summary>
/// Gets a session with or without an interceptor. This method is not called directly; instead,
/// it gets invoked from other public methods.
/// </summary>
private ISession GetSession(IInterceptor interceptor)
{
ISession session = ThreadSession;
if (session == null)
{
if (interceptor != null)
{
session = idadSessionFactory.OpenSession(interceptor);
}
else
{
session = idadSessionFactory.OpenSession();
}
ThreadSession = session;
}
return session;
}
public void CloseSession()
{
ISession session = ThreadSession;
ThreadSession = null;
if (session != null && session.IsOpen)
{
session.Close();
}
}
public void BeginTransaction()
{
ITransaction transaction = ThreadTransaction;
if (transaction == null)
{
transaction = GetSession().BeginTransaction();
ThreadTransaction = transaction;
}
}
public void CommitTransaction()
{
ITransaction transaction = ThreadTransaction;
try
{
if (transaction != null && !transaction.WasCommitted && !transaction.WasRolledBack)
{
transaction.Commit();
ThreadTransaction = null;
}
}
catch (HibernateException ex)
{
RollbackTransaction();
throw ex;
}
}
public void RollbackTransaction()
{
ITransaction transaction = ThreadTransaction;
try
{
ThreadTransaction = null;
if (transaction != null && !transaction.WasCommitted && !transaction.WasRolledBack)
{
transaction.Rollback();
}
}
catch (HibernateException ex)
{
throw ex;
}
finally
{
CloseSession();
}
}
/// <summary>
/// If within a web context, this uses <see cref="HttpContext" /> instead of the WinForms
/// specific <see cref="CallContext" />. Discussion concerning this found at
/// http://forum.springframework.net/showthread.php?t=572.
/// </summary>
private ITransaction ThreadTransaction
{
get
{
if (IsInWebContext())
{
return (ITransaction)HttpContext.Current.Items[TRANSACTION_KEY];
}
else
{
return (ITransaction)CallContext.GetData(TRANSACTION_KEY);
}
}
set
{
if (IsInWebContext())
{
HttpContext.Current.Items[TRANSACTION_KEY] = value;
}
else
{
CallContext.SetData(TRANSACTION_KEY, value);
}
}
}
/// <summary>
/// If within a web context, this uses <see cref="HttpContext" /> instead of the WinForms
/// specific <see cref="CallContext" />. Discussion concerning this found at
/// http://forum.springframework.net/showthread.php?t=572.
/// </summary>
private ISession ThreadSession
{
get
{
if (IsInWebContext())
{
return (ISession)HttpContext.Current.Items[SESSION_KEY];
}
else
{
return (ISession)CallContext.GetData(SESSION_KEY);
}
}
set
{
if (IsInWebContext())
{
HttpContext.Current.Items[SESSION_KEY] = value;
}
else
{
CallContext.SetData(SESSION_KEY, value);
}
}
}
private static bool IsInWebContext()
{
return HttpContext.Current != null;
}
private const string TRANSACTION_KEY = "CONTEXT_TRANSACTION";
private const string SESSION_KEY = "CONTEXT_SESSION";
[Obsolete("only until we can fix the session issue globally")]
internal ISession OpenSession()
{
return idadSessionFactory.OpenSession();
}
}
}
This is being called from a repository class like so:
public string getByName(string name)
{
return getByName(nHibernateSessionManager.Instance.GetSession(), name);
}
What I would really like to be able to do is the following:
public string getByName(string name, string clientConnectionString)
{
return getByName(nHibernateSessionManager.Instance.GetSession(clientConnectionString), name);
}
But I am having trouble modifying my existing session manager to accomodate this.
You appear to be asking to swap a connection for a given session. Or rather that is certainly what the code you have written is asking - "return a session identified by the name parameter, and it should also now use the connection string provided by this method."
That is not possible. NHibernate builds a session (and actually really a session factory) per connection and once built the factory and session are immutable. You cannot change connections for an existing session.
I got the impression that your application involves mostly in initial connection string that is the moving target, but after that your "real" session is on a single database. If that is the case, NHibernate can easily do this. If that is not the case, well, some things NHibernate is just not that well suited for. Maybe understanding a little more about the basis NHibernate operates on is helpful either way?
One of my genuine criticisms of NHibernate is that you have a somewhat arcane use of terminology and the well known unhelpful nature of it's exception messages. These coupled with the fact that what it is doing is in reality mechanically complicated tends to really obscure that there is a relatively simple and technically sound underlying model.
In this case, if you think about it this business of an immutable session makes a lot of sense. NHibernate connects to a database, but it also maintains objects in the session so they can be persisted back to that database at a later time. NHibernate does not support changing connections per session because there may already be other objects in the session and if you change connections their persistence is no longer assured.
Now, what you can do is create a factory/session per database for multiple databases and access them in one application, but objects still belong to their own session. You can even move objects to a new session with a different connection. In this case you have what would logically be a "replication" scenario. NHibernate supports this but you have to do most of the work. This also makes sense - they really cannot give you that as stable out of the box functionality, you have to manage a process like that on your own.
You can also build code to do exactly what you are asking. But think about what that is. Make a session, not per database, but only for this specific instance of this specific repository. I am thinking that is most likely not really what you want. But that is exactly what the semantics of your request are saying to do. Your existing class, On the other hand, was built on different semantics which are more typically what people want - "Build a session for this particular connection definition, i.e this database."
A real need to inject a connection string at the repository level implies that now not only is the database a moving target, but at the actual table level the target also moves. If that is the case, NHibernate is possibly not a good option. If that is not the case, you may be trying to mix programming paradigms. NHiberate imposes a few what I would call "assumptions" rather than any sort of real "limitations" and in return you don't have to write a bunch of code that would allow you a finer grain of control because often you really don't need that additional control.
Sorry if this is no longer a direct answer to your question, hopefully it is helpful somehow.
Original Answer:
Sure, since the connection info is in the authentication database this is easy.
1) Configure NHibernate in the "usual" fashion and point the config at the authentication database. Get the db connection for the user, and then close that session and session factory. You are done with that one now.
2) Create a new session etc this time in code instead of a config file.
class MyNewSession
{
private ISession _session;
private ISessionFactory _factory;
public void InitializeSession()
{
NHibernate.Cfg.Configuration config = new NHibernate.Cfg.Configuration();
config.Properties.Clear();
IDictionary props = new Hashtable();
// Configure properties as needed, this is pretty minimal standard config here.
// Can read in properties from your own xml file or whatever.
// Just shown hardcoded here.
props["proxyfactory.factory_class"] = "NHibernate.ByteCode.Castle.ProxyFactoryFactory, NHibernate.ByteCode.Castle";
props["connection.provider"] = "NHibernate.Connection.DriverConnectionProvider";
props["dialect"] = "NHibernate.Dialect.MsSql2000Dialect";
props["connection.driver_class"] = "NHibernate.Driver.SqlClientDriver";
props["connection.connection_string"] = "<YOUR CONNECTION STRING HERE>";
props["connection.isolation"] = "ReadCommitted";
foreach (DictionaryEntry de in props)
{
config.Properties.Add(de.Key.ToString(), de.Value.ToString());
}
// Everything from here on out is the standard NHibernate calls
// you already use.
// Load mappings etc, etc
// . . .
_factory = config.BuildSessionFactory();
_session = _factory.OpenSession();
}
}
I know this is old but if you have not found a solution I hope this will help,
I created a solution that uses multisessionfactory using unhaddins (I made alterations to suit my needs).
Basically the multisession factory creates session factories for each database and stores in Application object.
Depending on the client the call to getfactory("name of factory from factory config file") returns correct database to query on.
You will have to alter your management module to support this and all of your repositories to support the change in management. This may be impractical at first but you have to alter them anyway. Your calls from your repository can be something like this:
public string getByName(string name)
{
return getByName(nHibernateSessionManager.SessionFactoryManager.GetFactory(Session["session variable that holds client session factory name that was set on login"]).GetCurrentSession(), name);
}
or (creating a method in the sessionmanager to return session of a given factory) your code could be like this
public string getByName(string name)
{
return getByName(nHibernateSessionManager.GetSession(Session["session variable that holds client session factory name that was set on login"]), name);
}
I am new to MVVM and have written a small app to test the waters and get familiar with the pattern. The main function of my app takes too long to not have some sort of user feedback that the process is continuing along. What would be the recommended way to place the call in a separate thread and provide feedback for a progress bar? The ViewModel code for the function is below. Thanks for the help.
public DataView Data
{
get
{
return resultsView;
}
set
{
if (value == resultsView)
{
return;
}
resultsView = value;
RaisePropertyChanged("Data");
}
}
private void SetData()
{
Data = RetrieveData.GetPartData(SelectedTeam, SelectedYear).DefaultView;
}
public RelayCommand GetData
{
get;
private set;
}
/// <summary>
/// Initializes a new instance of the MainViewModel class.
/// </summary>
public MainViewModel()
{
// Initializers for other part of ViewModel
// Teams = RetrieveData.GetTeams();
// Years = RetrieveData.GetYears();
GetData = new RelayCommand(SetData);
}
I'm not completely versed on MVVM multi-threading yet, but this link seems quite do-able : WPF Multithreading: Using the BackgroundWorker and Reporting the Progress to the UI.
NOW, what I would try is something like this:
worker.DoWork += delegate(object s, DoWorkEventArgs args)
{
Data = RetrieveData.GetPartData(SelectedTeam, SelectedYear).DefaultView;
};
I'm trying to do some very simple request throttling on my ASP.NET web project. Currently I'm not interested in globally throttling requests against DOS attacks, but would like to artificially delay the reponse to all login attempts, just to make dictionary attacks a bit harder to do (more or less like Jeff Atwood outlined here).
How would you implement it? The näive way of doing it would be - I suppose - to simply call
Thread.Sleep();
somewhere during the request. Suggestions? :)
I got the same idea as you on how to improve the security of a login screen (and password reset screens). I'm going to implement this for my project and I'll share my story with you.
Requirements
My requirements are in following points:
Do not block individual users just because someone is trying to hack in
My user names are very easy to guess because they follow a certain pattern (and I do not like security by obscurity)
Do not waste server resources by sleeping on too many requests, the queue would overflow eventually and requests would start timing out
Provide a swift service to most users 99% of the time
Eliminate brute force attacks on the login screen
Handle distributed attacks as well
Needs to be reasonably thread-safe
Plan
So we shall have a list of failed attempts and their time stamp. Every time we have a login attempt, we'll check this list and the more there are failed attempts, the longer it will take to login. Each time we'll prune old entries by their time stamp. Beyond a certain threshold, no logins will be allowed and all login requests will be failed immediately (attack emergency shut-down).
We do not stop with the automatic protection. A notification should be sent to admins in case of the emergency shut-down so that the incident can be investigated and reparation measures can be taken. Our logs should hold a firm record of the failed attempts including the time, user name and source IP address for investigation.
The plan is to implement this as a statically declared queue, where failed attempts enqueue and old entries dequeue. the length of the queue is our indicator of severity. When I've got the code ready, I'll update the answer. I might include Keltex's suggestion too - releasing the response quickly and completing the login with another request.
Update: There is two things missing:
The redirect of the response to a wait page not to clog the request queue and that is a little biggie obviously. We need to give the user a token to check back later with another request. This could be another security hole so we need to be extremely cautious about handling this. Or just drop that Thread.Sleap(xxx) in the Action method :)
The IP, dooh, next time...
Let's see if we can get through that eventually...
What's done
ASP.NET page
ASP.NET UI Page should have minimum hassle, then we get an instance of a Gate like this:
static private LoginGate Gate = SecurityDelayManager.Instance.GetGate<LoginGate>();
And after login (or password reset) attempt, call:
SecurityDelayManager.Instance.Check(Gate, Gate.CreateLoginAttempt(success, UserName));
ASP.NET handling code
The LoginGate is implemented inside the AppCode of the ASP.NET project so it has access to all the front-end goodies. It implements the interface IGate which is used by the backend SecurityDelayManager instance. The Action method needs to be completed with wait redirection.
public class LoginGate : SecurityDelayManager.IGate
{
#region Static
static Guid myID = new Guid("81e19a1d-a8ec-4476-a187-3130361a9006");
static TimeSpan myTF = TimeSpan.FromHours(24);
#endregion
#region Private Types
class LoginAttempt : Attempt { }
class PasswordResetAttempt : Attempt { }
class PasswordResetRequestAttempt : Attempt { }
abstract class Attempt : SecurityDelayManager.IAttempt
{
public bool Successful { get; set; }
public DateTime Time { get; set; }
public String UserName { get; set; }
public string SerializeForAuditLog()
{
return ToString();
}
public override string ToString()
{
return String.Format("{2} Successful:{0} #{1}", Successful, Time, GetType().Name);
}
}
#endregion
#region Attempt creation utility methods
public SecurityDelayManager.IAttempt CreateLoginAttempt(bool success, string userName)
{
return new LoginAttempt() { Successful = success, UserName = userName, Time = DateTime.Now };
}
public SecurityDelayManager.IAttempt CreatePasswordResetAttempt(bool success, string userName)
{
return new PasswordResetAttempt() { Successful = success, UserName = userName, Time = DateTime.Now };
}
public SecurityDelayManager.IAttempt CreatePasswordResetRequestAttempt(bool success, string userName)
{
return new PasswordResetRequestAttempt() { Successful = success, UserName = userName, Time = DateTime.Now };
}
#endregion
#region Implementation of SecurityDelayManager.IGate
public Guid AccountID { get { return myID; } }
public bool ConsiderSuccessfulAttemptsToo { get { return false; } }
public TimeSpan SecurityTimeFrame { get { return myTF; } }
public SecurityDelayManager.ActionResult Action(SecurityDelayManager.IAttempt attempt, int attemptsCount)
{
var delaySecs = Math.Pow(2, attemptsCount / 5);
if (delaySecs > 30)
{
return SecurityDelayManager.ActionResult.Emergency;
}
else if (delaySecs < 3)
{
return SecurityDelayManager.ActionResult.NotDelayed;
}
else
{
// TODO: Implement the security delay logic
return SecurityDelayManager.ActionResult.Delayed;
}
}
#endregion
}
Backend somewhat thread-safe management
So this class (in my core lib) will handle the multi-threaded counting of attempts:
/// <summary>
/// Helps to count attempts and take action with some thread safety
/// </summary>
public sealed class SecurityDelayManager
{
ILog log = LogManager.GetLogger(typeof(SecurityDelayManager).FullName + ".Log");
ILog audit = LogManager.GetLogger(typeof(SecurityDelayManager).FullName + ".Audit");
#region static
static SecurityDelayManager me = new SecurityDelayManager();
static Type igateType = typeof(IGate);
public static SecurityDelayManager Instance { get { return me; } }
#endregion
#region Types
public interface IAttempt
{
/// <summary>
/// Is this a successful attempt?
/// </summary>
bool Successful { get; }
/// <summary>
/// When did this happen
/// </summary>
DateTime Time { get; }
String SerializeForAuditLog();
}
/// <summary>
/// Gate represents an entry point at wich an attempt was made
/// </summary>
public interface IGate
{
/// <summary>
/// Uniquely identifies the gate
/// </summary>
Guid AccountID { get; }
/// <summary>
/// Besides unsuccessful attempts, successful attempts too introduce security delay
/// </summary>
bool ConsiderSuccessfulAttemptsToo { get; }
TimeSpan SecurityTimeFrame { get; }
ActionResult Action(IAttempt attempt, int attemptsCount);
}
public enum ActionResult { NotDelayed, Delayed, Emergency }
public class SecurityActionEventArgs : EventArgs
{
public SecurityActionEventArgs(IGate gate, int attemptCount, IAttempt attempt, ActionResult result)
{
Gate = gate; AttemptCount = attemptCount; Attempt = attempt; Result = result;
}
public ActionResult Result { get; private set; }
public IGate Gate { get; private set; }
public IAttempt Attempt { get; private set; }
public int AttemptCount { get; private set; }
}
#endregion
#region Fields
Dictionary<Guid, Queue<IAttempt>> attempts = new Dictionary<Guid, Queue<IAttempt>>();
Dictionary<Type, IGate> gates = new Dictionary<Type, IGate>();
#endregion
#region Events
public event EventHandler<SecurityActionEventArgs> SecurityAction;
#endregion
/// <summary>
/// private (hidden) constructor, only static instance access (singleton)
/// </summary>
private SecurityDelayManager() { }
/// <summary>
/// Look at the attempt and the history for a given gate, let the gate take action on the findings
/// </summary>
/// <param name="gate"></param>
/// <param name="attempt"></param>
public ActionResult Check(IGate gate, IAttempt attempt)
{
if (gate == null) throw new ArgumentException("gate");
if (attempt == null) throw new ArgumentException("attempt");
// get the input data befor we lock(queue)
var cleanupTime = DateTime.Now.Subtract(gate.SecurityTimeFrame);
var considerSuccessful = gate.ConsiderSuccessfulAttemptsToo;
var attemptSuccessful = attempt.Successful;
int attemptsCount; // = ?
// not caring too much about threads here as risks are low
Queue<IAttempt> queue = attempts.ContainsKey(gate.AccountID)
? attempts[gate.AccountID]
: attempts[gate.AccountID] = new Queue<IAttempt>();
// thread sensitive - keep it local and short
lock (queue)
{
// maintenance first
while (queue.Count != 0 && queue.Peek().Time < cleanupTime)
{
queue.Dequeue();
}
// enqueue attempt if necessary
if (!attemptSuccessful || considerSuccessful)
{
queue.Enqueue(attempt);
}
// get the queue length
attemptsCount = queue.Count;
}
// let the gate decide what now...
var result = gate.Action(attempt, attemptsCount);
// audit log
switch (result)
{
case ActionResult.Emergency:
audit.ErrorFormat("{0}: Emergency! Attempts count: {1}. {2}", gate, attemptsCount, attempt.SerializeForAuditLog());
break;
case ActionResult.Delayed:
audit.WarnFormat("{0}: Delayed. Attempts count: {1}. {2}", gate, attemptsCount, attempt.SerializeForAuditLog());
break;
default:
audit.DebugFormat("{0}: {3}. Attempts count: {1}. {2}", gate, attemptsCount, attempt.SerializeForAuditLog(), result);
break;
}
// notification
if (SecurityAction != null)
{
var ea = new SecurityActionEventArgs(gate, attemptsCount, attempt, result);
SecurityAction(this, ea);
}
return result;
}
public void ResetAttempts()
{
attempts.Clear();
}
#region Gates access
public TGate GetGate<TGate>() where TGate : IGate, new()
{
var t = typeof(TGate);
return (TGate)GetGate(t);
}
public IGate GetGate(Type gateType)
{
if (gateType == null) throw new ArgumentNullException("gateType");
if (!igateType.IsAssignableFrom(gateType)) throw new Exception("Provided gateType is not of IGate");
if (!gates.ContainsKey(gateType) || gates[gateType] == null)
gates[gateType] = (IGate)Activator.CreateInstance(gateType);
return gates[gateType];
}
/// <summary>
/// Set a specific instance of a gate for a type
/// </summary>
/// <typeparam name="TGate"></typeparam>
/// <param name="gate">can be null to reset the gate for that TGate</param>
public void SetGate<TGate>(TGate gate) where TGate : IGate
{
var t = typeof(TGate);
SetGate(t, gate);
}
/// <summary>
/// Set a specific instance of a gate for a type
/// </summary>
/// <param name="gateType"></param>
/// <param name="gate">can be null to reset the gate for that gateType</param>
public void SetGate(Type gateType, IGate gate)
{
if (gateType == null) throw new ArgumentNullException("gateType");
if (!igateType.IsAssignableFrom(gateType)) throw new Exception("Provided gateType is not of IGate");
gates[gateType] = gate;
}
#endregion
}
Tests
And I've made a test fixture for that:
[TestFixture]
public class SecurityDelayManagerTest
{
static MyTestLoginGate gate;
static SecurityDelayManager manager;
[SetUp]
public void TestSetUp()
{
manager = SecurityDelayManager.Instance;
gate = new MyTestLoginGate();
manager.SetGate(gate);
}
[TearDown]
public void TestTearDown()
{
manager.ResetAttempts();
}
[Test]
public void Test_SingleFailedAttemptCheck()
{
var attempt = gate.CreateLoginAttempt(false, "user1");
Assert.IsNotNull(attempt);
manager.Check(gate, attempt);
Assert.AreEqual(1, gate.AttemptsCount);
}
[Test]
public void Test_AttemptExpiration()
{
var attempt = gate.CreateLoginAttempt(false, "user1");
Assert.IsNotNull(attempt);
manager.Check(gate, attempt);
Assert.AreEqual(1, gate.AttemptsCount);
}
[Test]
public void Test_SingleSuccessfulAttemptCheck()
{
var attempt = gate.CreateLoginAttempt(true, "user1");
Assert.IsNotNull(attempt);
manager.Check(gate, attempt);
Assert.AreEqual(0, gate.AttemptsCount);
}
[Test]
public void Test_ManyAttemptChecks()
{
for (int i = 0; i < 20; i++)
{
var attemptGood = gate.CreateLoginAttempt(true, "user1");
manager.Check(gate, attemptGood);
var attemptBaad = gate.CreateLoginAttempt(false, "user1");
manager.Check(gate, attemptBaad);
}
Assert.AreEqual(20, gate.AttemptsCount);
}
[Test]
public void Test_GateAccess()
{
Assert.AreEqual(gate, manager.GetGate<MyTestLoginGate>(), "GetGate should keep the same gate");
Assert.AreEqual(gate, manager.GetGate(typeof(MyTestLoginGate)), "GetGate should keep the same gate");
manager.SetGate<MyTestLoginGate>(null);
var oldGate = gate;
var newGate = manager.GetGate<MyTestLoginGate>();
gate = newGate;
Assert.AreNotEqual(oldGate, newGate, "After a reset, new gate should be created");
manager.ResetAttempts();
Test_ManyAttemptChecks();
manager.SetGate(typeof(MyTestLoginGate), oldGate);
manager.ResetAttempts();
Test_ManyAttemptChecks();
}
}
public class MyTestLoginGate : SecurityDelayManager.IGate
{
#region Static
static Guid myID = new Guid("81e19a1d-a8ec-4476-a187-5130361a9006");
static TimeSpan myTF = TimeSpan.FromHours(24);
class LoginAttempt : Attempt { }
class PasswordResetAttempt : Attempt { }
abstract class Attempt : SecurityDelayManager.IAttempt
{
public bool Successful { get; set; }
public DateTime Time { get; set; }
public String UserName { get; set; }
public string SerializeForAuditLog()
{
return ToString();
}
public override string ToString()
{
return String.Format("Attempt {2} Successful:{0} #{1}", Successful, Time, GetType().Name);
}
}
#endregion
#region Test properties
public int AttemptsCount { get; private set; }
#endregion
#region Implementation of SecurityDelayManager.IGate
public Guid AccountID { get { return myID; } }
public bool ConsiderSuccessfulAttemptsToo { get { return false; } }
public TimeSpan SecurityTimeFrame { get { return myTF; } }
public SecurityDelayManager.IAttempt CreateLoginAttempt(bool success, string userName)
{
return new LoginAttempt() { Successful = success, UserName = userName, Time = DateTime.Now };
}
public SecurityDelayManager.IAttempt CreatePasswordResetAttempt(bool success, string userName)
{
return new PasswordResetAttempt() { Successful = success, UserName = userName, Time = DateTime.Now };
}
public SecurityDelayManager.ActionResult Action(SecurityDelayManager.IAttempt attempt, int attemptsCount)
{
AttemptsCount = attemptsCount;
return attemptsCount < 3
? SecurityDelayManager.ActionResult.NotDelayed
: attemptsCount < 30
? SecurityDelayManager.ActionResult.Delayed
: SecurityDelayManager.ActionResult.Emergency;
}
#endregion
}
I would place the delay on the server validation portion where it won't attempt to validate (come back automatically as false have a message saying the user has to wait so many seconds before making another attempt). another answer until so many seconds have passed. Doing the thread.sleep will prevent one browser from making another attempt, but it won't stop a distributed attack where someone has multiple programs trying to login as the user simultaneously.
Another possibility is that the time between attempts varies by how many attempts are made to login. So the second attempt they have a one second wait, the third is maybe 2, the third is 4 and so on. That way you don't have a legitimate user having to wait 15 seconds between login attempts because they mistyped their password incorrectly the first time.
Kevin makes a good point about not wanting to tie up your request thread. One answer would be to make the login an asychronous request. The asychronous process would just be to wait for the amount of time you choose (500ms?). Then you wouldn't block the request thread.
I don't think this will help you thwart DOS attacks. If you sleep the request thread, you are still allowing the request to occupy your thread pool and still allow the attacker to bring your web service to its knees.
Your best bet may be to lock out requests after a specified number of failed attempts based on the attempted login name, source IP, etc, to try and target the source of the attack without detriment to your valid users.
I know it's not what you're asking, but you could implement an account lockout instead. That way, you give them their guesses and then can make them wait any amount of time you want before they can start guessing again. :)
I don't think what you are asking for is quite an efficient way in a web enviornment. Login screens' purpose is to provide an easy way for 'users' to gain access to your services and should be easy and fast to use. So you should not make a user wait considering 99% of the them will not be bad-minded.
Sleep.Trhead also has the potential to place a huge load on your server should there be a lot of concurrent users trying to log in. Potential options would be:
Block the IP for (e.g.) the end of the session for x number of unsuccessful login attempts
Provide a captcha
of course these are not all the options but still I am sure more people will have more ideas...