Odata V4 with DateTime - .net-core

Hi I have problems when I use ODate for comparing my dates. When I do this next request:
https://localhost:44391/api/v1/Invoice/OData?$top=11&$skip=0&$filter=InvoiceDate lt 2014-10-30
I obtain the next error:
{
"StatusCode": 500,
"Message": "Unable to cast object of type 'Microsoft.OData.UriParser.ConvertNode' to type 'Microsoft.OData.UriParser.ConstantNode'."
}
The dates that I have in my database is looked like at nexts:
2013-12-30 00:00:00.000
2013-12-30 00:00:00.000
2017-07-14 00:00:00.000
In my class Startup I had the next:
private static IEdmModel GetEdmModel()
{
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
List<string> listaControllers = GetControllers();
foreach (string controller in listaControllers)
{
builder.EntitySet<BaseEntityDto>(controller);
}
return builder.GetEdmModel();
}
private static List<string> GetControllers()
{
Type parentType = typeof(ApiControllerBase<,,>);
Assembly assembly = Assembly.GetExecutingAssembly();
return assembly.GetTypes().Where(x => x.BaseType.Name == parentType.Name).Select(x => x.Name.Replace("Controller", "")).ToList<string>();
}
app.UseMvc(routeBuilder =>
{
routeBuilder.Expand().Select().Filter().Count().OrderBy().MaxTop(null);
routeBuilder.EnableDependencyInjection();
routeBuilder.MapODataServiceRoute("odata", "odata", GetEdmModel());
});
And in my entity Invoice.cs I had the next attribute:
public DateTime InvoiceDate { get; set; }
And When I executed the last query in the Postman the controller (Invoicecontroller.cs) that is executed is the next:
[HttpGet("OData")]
public async Task<PageResult<InvoiceDto>> Get(ODataQueryOptions<InvoiceDto> queryOptions)
{
var options = new ODataQueryListOptions(queryOptions);
var result = await InvoiceQueryService.GetAll(options.QueryListOptions);
var count = await InvoiceQueryService.Count(options.QueryListOptions);
return new PageResult<InvoiceDto>(result, null, count);
}
I don't know where the problem ocurred, and I need more information for solving the problem. Thanks to everyone for trying to solve this thing. I want to say that I use Views no Tables.

Only put this in my entity solve my problem:
[Column(TypeName = "datetime")]
public DateTime InvoiceDate { get; set; }
Thanks for all community for reading my question.

Related

is it a good idea to do transformation in a database model with ASP.Net

we are a small development team.
We develop in ASP.NET and we are starting to use generic controllers and services.
The goal is to have solid methods for things that are repetitive.
What we ask ourselves is if it is a good idea to do some transformation in the data models to allow us to reuse our functions that we know are working?
Exemple: we have a combobox and we want to manage the display and search. It's always the same and redundant.
This is my class
[Table("stage.Test")]
public partial class Test : IBaseEntity, ICombobox
{
public virtual Product Product { get; set; }
public string nom { get; set; }
public string prenom { get; set; }
public string title { get; set; }
[NotMapped]
public virtual string AffichageCombobox => nom + prenom;
[NotMapped]
public virtual string TexteRecherche => Product.Gabarit.Description;
}
as you can see i have two columns with the tag [NotMapped]. These are the columns in the interface ICombobox
public interface ICombobox
{
string AffichageCombobox { get;}
string TexteRecherche { get; }
}
this is the first service where I use one of my two columns which redirects to other columns. [We use the column "AffichageCombobox" from the model]
public List<ComboboxViewModel> GetComboboxViewModel(int? id, bool actifseulement, string text)
{
var query = _requestDatabaseService.GetComboboxQuery<T>(id, actifseulement, text);
var list = query.Select(table => new ComboboxViewModel
{
Id = table.Id,
AffichageCombobox = table.DateHFin == null ? table.AffichageCombobox : table.AffichageCombobox + " (inactif)"
}).ToList();
return list;
}
This is the RequestDatabaseService [We use the column "TexteRecherche" from the model]
public List<T> GetComboboxQuery<T>(int? id, bool actifseulement, string text) where T : class, IBaseEntity, ICombobox
{
text = text.ToLower();
var list = _dbContext.Set<T>()
.If(id.HasValue,
q => q.Where(x => x.Id == id))
.If(actifseulement,
q => q.Where(x => x.DateHFin == null))
.If(text != "",
q => q.Where(x => x.TexteRecherche.ToLower() == text))
.ToList();
return list;
}
As you can see, I am using an interface to add columns to redirect to the correct columns to my data model to avoid overriding my methods for two column.
Is it a good idea, a good practice ?
What do you think is the best practice if we want to do generic functions, but the columns are not called the same way?
Thank you!
Your solution has a lot of weaknesses
You have extended Model to handle specific UI cases. In my opinion it is bad practice.
Your virtual properties will not work in LINQ query. EF translates only Expression because it canot look into compiled property body.
What we can do here is simplifying of building such comboboxes. I have defind set fo extensions which can be reused for such scenarios. Sorry if there some mistakes, written from memory.
How it can be used:
Assuming that GetComboboxViewModel is not in generic class
public List<ComboboxViewModel> GetComboboxViewModel(int? id, bool actifseulement, string text)
{
// uncover DbContext. All that we need is IQueryable<Test>
var ctx = _requestDatabaseService.GetContext();
var query = ctx.Test.AsQueryable();
var comboItems = query
.FilterItems(id, actifseulement)
.GetComboboxQuery(text, e => e.Product.Gabarit.Description, e => e.nom + e.prenom)
.ToList();
return comboItems;
}
Think about this solution and yes, we can register somewhere pair of Lmbdas Dictionary<Type, (LambdaExpression: searchProp, LambdaExpression: displayProp)> and dynamically build call above.
Realisation:
public static class QueryableExtensions
{
// more simlified version for filtering
public static IQueryable<T> WhereIf(this IQueryable<T> query, bool condition, Expression<Func<T, bool>> predicate)
{
return condition ? query.Where(predicate) : query;
}
// handy function for filtering
public static IQueryable<T> FilterItems<T>(this IQueryable<T> query, int? id, bool onlyActive)
where T : IBaseEntity
{
query = query
.WhereIf(id.HasValue, x => x.Id == id)
.WhereIf(onlyActive, x => x.DateHFin == null)
return query;
}
// dynamic generation of filtering and projection
public static IQueryable<ComboboxViewModel> GetComboboxQuery<T>(this IQueryable<T> query, string text, Expression<Func<T, string>> searchProp, Expression<Func<T, string>> dsiplayProp)
where T : IBaseEntity
{
if (!string.IsNullOrEmpty(text))
{
text = text.ToLower();
// defining search pattern
// this also extension point, you may use here `Contains` or FullText search functions
Expression<Func<string, string, bool>> filterFunc = (s, t) => s.ToLower() == t;
// reusing parameter from searchProp lambda
var param = searchProp.Parameters[0];
// applying pattern to searchprop
var filterBody = ExpressionReplacer.GetBody(filterFunc, searchProp.Body, Expression.Constant(text));
// applying generated filter
var filterPredicate = Expression.Lambda<Func<T, bool>>(filterBody, param);
query = query.Where(filterPredicate);
}
// defining template for Select
Expression<Func<T, string, ComboboxViewModel>> createTemplate = (entity, dp) => new ComboboxViewModel
{
Id = entity.Id,
AffichageCombobox = entity.DateHFin == null ? dp : dp + " (inactif)"
};
// reusing parameter from dsiplayProp lambda
var entityParam = dsiplayProp.Parameters[0];
// injecting dsiplayProp into createTemplate
var selectBody = ExpressionReplacer.GetBody(createTemplate, entityParam, dsiplayProp.Body);
var selectLambda = Expression.Lambda<Func<T, ComboboxViewModel>>(selectBody, entityParam);
// applying projection
var comboQuery = query.Select(selectLambda);
return comboQuery;
}
// helper class for correcting expressions
class ExpressionReplacer : ExpressionVisitor
{
readonly IDictionary<Expression, Expression> _replaceMap;
public ExpressionReplacer(IDictionary<Expression, Expression> replaceMap)
{
_replaceMap = replaceMap ?? throw new ArgumentNullException(nameof(replaceMap));
}
public override Expression Visit(Expression exp)
{
if (exp != null && _replaceMap.TryGetValue(exp, out var replacement))
return replacement;
return base.Visit(exp);
}
public static Expression Replace(Expression expr, Expression toReplace, Expression toExpr)
{
return new ExpressionReplacer(new Dictionary<Expression, Expression> { { toReplace, toExpr } }).Visit(expr);
}
public static Expression Replace(Expression expr, IDictionary<Expression, Expression> replaceMap)
{
return new ExpressionReplacer(replaceMap).Visit(expr);
}
public static Expression GetBody(LambdaExpression lambda, params Expression[] toReplace)
{
if (lambda.Parameters.Count != toReplace.Length)
throw new InvalidOperationException();
return new ExpressionReplacer(Enumerable.Range(0, lambda.Parameters.Count)
.ToDictionary(i => (Expression) lambda.Parameters[i], i => toReplace[i])).Visit(lambda.Body);
}
}
}
Well, after writing this sample, I think, it can be cardinally simplified by using LINQKit. Will post another answer with LINQKit usage if you are interested,

ASP.NET Core ModelBindingContext Uses Only 1 Value Provider (Ignores RouteDataValueProvider)

I'm currently converting a ASP.NET library to ASP.NET Core that's heavy on Model Binding, and one issue I'm unable to resolve is that for cases where a model binder wants to try and get values via Value Providers both from (From)Query and (From)Route (as in, they have different BindingSource) it can only access one, resulting in the binding to fail since it fails to find the target value.
While debugging the application I can see that the ModelBindingContext does have both value providers in its private OriginalValueProvider, but when trying to access the ValueProvider it only returns one of the providers - in this case, only the QueryStringValueProvider and not the RouteValueProvider).
This seems not to have been the behavior back in regular ASP.NET, as there the existing application happily uses both value providers to find its value - and does so successfully. Is this some breaking change between System.Web.Http.ModelBinding -> Microsoft.AspNetCore.Mvc.ModelBinding? Is there some option that must be enabled? Some guidance would be appreciated.
Here follows some screen caps from my debugging:
System.Web.Http original:
Microsoft.AspNetCore.Mvc rework:
Microsoft.AspNetCore.Mvc OriginalValueProvider(s) proof:
Edit:
And here follows some code snippets, as requested:
Controller:
[HttpGet]
[Route("accounts/{accountId}/catalogs/{catalogId}/medias", Name = "GetCatalogMedias")]
[ProducesResponseType(typeof(IList<MediaResponse>), (int)HttpStatusCode.OK)]
public async Task<IActionResult> GetCatalogMedias(
[FromRoute] string accountId,
[FromRoute] string catalogId,
[FromQuery, SortingFieldDefaultValue("created", SortingDirection.Desc)] IEnumerable<SortingField> sort,
[FromQuery] QueryTree<MediaResponse> q = null,
[FromQuery, Range(0, int.MaxValue)] int offset = 0,
[FromQuery, Range(1, 200)] int limit = 200)
{
if (!ModelState.IsValid)
{
return await _responseFactory.CreateBadRequest(ModelState);
}
Binder:
public class CatalogMediasQueryModelBinder<T> : BaseBinder, IModelBinder
{
private readonly QueryModelBinder _queryModelBinder;
public CatalogMediasQueryModelBinder(QueryModelBinder queryModelBinder)
{
_queryModelBinder = queryModelBinder;
}
public async Task BindModelAsync(ModelBindingContext bindingContext)
{
var success = TryGetValueProviderResult(bindingContext, out var catalogId, "catalogId");
if (!success)
{
bindingContext.ModelState.AddModelError(bindingContext.ModelName, "Missing catalogId");
return;
}
//...
Base Binder:
public class BaseBinder
{
protected bool TryGetValueProviderResult(ModelBindingContext bindingContext, out string result, string findValue = null)
{
if (bindingContext?.ValueProvider == null)
{
throw new ArgumentNullException(nameof(bindingContext));
}
result = null;
var modelName = findValue ?? bindingContext.ModelName;
var valueProviderResult = bindingContext.ValueProvider.GetValue(modelName);
if (valueProviderResult == ValueProviderResult.None)
{
return false;
}
bindingContext.ModelState.SetModelValue(modelName, valueProviderResult);
var value = valueProviderResult.FirstValue;
if (string.IsNullOrWhiteSpace(value))
{
return false;
}
result = value;
return true;
}
protected Task SetModelBindingResult<T>(ModelBindingContext bindingContext, T value)
{
bindingContext.Result = ModelBindingResult.Success(value);
return Task.CompletedTask;
}
}

How to use tempdata to return error message

I am trying to use temp data to return messages but it gives an error :
InvalidOperationException: The 'Microsoft.AspNetCore.Mvc.ViewFeatures.Internal.TempDataSerializer' cannot serialize an object of type
I am already using
services.AddMvc().AddSessionStateTempDataProvider();
app.UseSession()
services.AddSession(options =>
{
// Set a short timeout for easy testing.
options.IdleTimeout = TimeSpan.FromSeconds(10);
options.Cookie.HttpOnly = true;
});
Here is my shared
FlashMessages.cshtml :
#using EnduroMotors.ViewModels
#{
var errorMessages = TempData["_error_messages"] as List<FlashMessageModel>
?? new List<FlashMessageModel>();
var warningMessages = TempData["_warning_messages"] as
List<FlashMessageModel> ?? new List<FlashMessageModel>();
var successMessages = TempData["_success_messages"] as
List<FlashMessageModel> ?? new List<FlashMessageModel>();
var infoMessages = TempData["_info_messages"] as List<FlashMessageModel> ??
new List<FlashMessageModel>();
}
Here is my viewmodel :
FlashMessageModel
public class FlashMessageModel
{
public string Title { get; set; }
public string Message { get; set; }
}
And here is use in controller :
Controller
protected void ShowSuccessMessage(string message, string title =
"Success!")
{
var messages =
(List<FlashMessageModel>)TempData["_success_messages"] ?? new
List<FlashMessageModel>();
messages.Add(new FlashMessageModel
{
Title = title,
Message = message
});
TempData["_success_messages"] = messages;
}
using this with return
ShowSuccessMessage("You have completed.");
it should show success message in index with #{Html.RenderPartial("FlashMessages");} but instead it gives
InvalidOperationException: The 'Microsoft.AspNetCore.Mvc.ViewFeatures.Internal.TempDataSerializer' cannot serialize an object of type 'EnduroMotors.ViewModels.FlashMessageModel'.
Microsoft.AspNetCore.Mvc.ViewFeatures.Internal.TempDataSerializer.EnsureObjectCanBeSerialized(object item)
TempData serialises objects to strings for storage. It supports string, int and boolean types natively. If you want to store more complex types, you have to serialise (and deserialise) them yourself. JSON is the recommended format. The following extension methods use the JSON.NET JsonConvert static methods to do this:
public static class TempDataExtensions
{
public static void Set<T>(this ITempDataDictionary tempData, string key, T value) where T : class
{
tempData[key] = JsonConvert.SerializeObject(value);
}
public static T Get<T>(this ITempDataDictionary tempData, string key) where T : class
{
tempData.TryGetValue(key, out object o);
return o ?? JsonConvert.DeserializeObject<T>((string)o);
}
}
You can read more about this here: https://www.learnrazorpages.com/razor-pages/tempdata#limitations

Why is my DataContractJsonSerializer failing on the call to ReadObject()?

I am trying to deserialize some json received from a Web API method being called from a .NET 3.5 Winforms app based on this code: http://msdn.microsoft.com/en-us/library/bb412179(v=vs.90).aspx
The json is being returned, but upon deserialization, it is failing to grab root and therefore growling:
Here is the client code in question:
try
{
var client = new RestClient();
client.BaseUrl = "http://localhost:48614/"; // <-- this works
var request = new RestRequest();
request.Resource = "api/departments/"; // can replace this with other data, such as redemptions, etc.
RestResponse response = client.Execute(request) as RestResponse;
if ((response.StatusCode == HttpStatusCode.OK) && (response.ResponseStatus == ResponseStatus.Completed)) // Both are probably not necessary
{
MessageBox.Show(string.Format("Content is {0}", response.Content));
// from http://msdn.microsoft.com/en-us/library/bb412179(v=vs.90).aspx
MemoryStream deptStream = new MemoryStream();
DataContractJsonSerializer cereal = new DataContractJsonSerializer(typeof(Department));
deptStream.Position = 0;
Department dept = (Department)cereal.ReadObject(deptStream);
MessageBox.Show(string.Format("accountId is {0}, deptName is {1}", dept.AccountId, dept.DeptName));
}
else
{
MessageBox.Show(string.Format("Status code is {0} ({1}); response status is {2}",
response.StatusCode, response.StatusDescription, response.ResponseStatus));
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
The response.Content line is doing just fine, displaying the json data in the dialog.
The Department data is defined this way in the .NET 4 ASP.NET / Web API app:
namespace DuckbilledPlatypusServerWebAPI.Models
{
public class Department
{
[Key]
public int Id { get; set; }
[Required]
public string AccountId { get; set; }
[Required]
public string DeptName { get; set; }
}
}
...and this way in the .NET 3.5 Winforms app that receives the data:
[DataContract]
public class Department
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string AccountId { get; set; }
[DataMember]
public string DeptName { get; set; }
}
So what does it yet need to work? How am I to supply it with a 'root' element, as it seems to be demanding?
UPDATE
Badri's answer solves the err msg, but I'm still not getting any data to work with the DataContractJsonSerializer, or I'm accessing it wrong. Here is my code now:
MessageBox.Show(string.Format("Content is {0}", response.Content));
byte[] bytes = Encoding.UTF8.GetBytes(response.Content);
MemoryStream deptStream = new MemoryStream(bytes);
deptStream.Position = 0;
DataContractJsonSerializer jasonCereal = new DataContractJsonSerializer(typeof(Department));
Department dept = (Department)jasonCereal.ReadObject(deptStream);
MessageBox.Show(string.Format("accountId is {0}, deptName is {1}", dept.AccountId, dept.DeptName));
...and, although the first message box shows the jsonarray:
...the second one says accountId and deptName are empty strings. In what way am I maltrreating DataContractJsonSerializer?
deptStream is newed up but where do you load the JSON response returned into the MemoryStream, before the deserialization. You should do something like this.
byte[] bytes = Encoding.UTF8.GetBytes(response.Content);
MemoryStream deptStream = new MemoryStream(bytes);
deptStream.Position = 0;
// Deserialize now
UPDATE
Your JSON corresponds to a list of Department objects not a single Department object. Try something like this.
var jasonCereal = new DataContractJsonSerializer(typeof(List<Department>));
var depts = (List<Department>)jasonCereal.ReadObject(deptStream);
foreach(var dept in depts)
MessageBox.Show(
String.Format("accountId is {0}, deptName is {1}",
dept.AccountId, dept.DeptName));

Using one session per request, how to handle updating child objects

I'm having some serious issues with Fluent Nhibernate in my ASP.NET WebForms app when trying to modify a child object and then saving the parent object.
My solution is currently made of 2 projects :
Core : A class library where all entities & repositories classes are located
Website : The ASP.NET 4.5 WebForms application
Here is my simple mapping for my Employee object:
public class EmployeeMap : ClassMap<Employee>
{
public EmployeeMap()
{
Id(x => x.Id).GeneratedBy.Identity();
Map(x => x.DateCreated);
Map(x => x.Username);
Map(x => x.FirstName);
Map(x => x.LastName);
HasMany(x => x.TimeEntries).Inverse().Cascade.All().KeyColumn("Employee_id");
}
}
Here is my my mapping for the TimeEntry object:
public class TimeEntryMap : ClassMap<TimeEntry>
{
public TimeEntryMap()
{
Id(x => x.Id).GeneratedBy.Identity();
Map(x => x.DateCreated);
Map(x => x.Date);
Map(x => x.Length);
References(x => x.Employee).Column("Employee_id").Not.Nullable();
}
}
As stated in the title, i'm using one session per request in my web app, using this code in Gobal.asax:
public static ISessionFactory SessionFactory = Core.SessionFactoryManager.CreateSessionFactory();
public static ISession CurrentSession
{
get { return (ISession)HttpContext.Current.Items["current.session"]; }
set { HttpContext.Current.Items["current.session"] = value; }
}
protected Global()
{
BeginRequest += delegate
{
System.Diagnostics.Debug.WriteLine("New Session");
CurrentSession = SessionFactory.OpenSession();
};
EndRequest += delegate
{
if (CurrentSession != null)
CurrentSession.Dispose();
};
}
Also, here is my SessionFactoryManager class:
public class SessionFactoryManager
{
public static ISession CurrentSession;
public static ISessionFactory CreateSessionFactory()
{
return Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2008.ConnectionString(c => c.FromConnectionStringWithKey("Website.Properties.Settings.WebSiteConnString")))
.Mappings(m => m
.FluentMappings.AddFromAssembly(Assembly.GetExecutingAssembly()))
.ExposeConfiguration(cfg => new SchemaUpdate(cfg).Execute(false, true))
.BuildSessionFactory();
}
public static ISession GetSession()
{
return (ISession)HttpContext.Current.Items["current.session"];
}
}
Here is one of my repository class, the one i use to handle the Employee's object data operations:
public class EmployeeRepository<T> : IRepository<T> where T : Employee
{
private readonly ISession _session;
public EmployeeRepository(ISession session)
{
_session = session;
}
public T GetById(int id)
{
T result = null;
using (ITransaction tx = _session.BeginTransaction())
{
result = _session.Get<T>(id);
tx.Commit();
}
return result;
}
public IList<T> GetAll()
{
IList<T> result = null;
using (ITransaction tx = _session.BeginTransaction())
{
result = _session.Query<T>().ToList();
tx.Commit();
}
return result;
}
public bool Save(T item)
{
var result = false;
using (ITransaction tx = _session.BeginTransaction())
{
_session.SaveOrUpdate(item);
tx.Commit();
result = true;
}
return result;
}
public bool Delete(T item)
{
var result = false;
using (ITransaction tx = _session.BeginTransaction())
{
_session.Delete(_session.Load(typeof (T), item.Id));
tx.Commit();
result = true;
}
return result;
}
public int Count()
{
var result = 0;
using (ITransaction tx = _session.BeginTransaction())
{
result = _session.Query<T>().Count();
tx.Commit();
}
return result;
}
}
Now, here is my problem. When i'm trying to insert Employee(s), everything is fine. Updating is also perfect... well, as long as i'm not updating one of the TimeEntry object referenced in the "TimeEntries" property of Employee...
Here is where an exception is raised (in a ASPX file of the web project):
var emp = new Employee(1);
foreach (var timeEntry in emp.TimeEntries)
{
timeEntry.Length += 1;
}
emp.Save();
Here is the exception that is raised:
[NonUniqueObjectException: a different object with the same identifier
value was already associated with the session: 1, of entity:
Core.Entities.Employee]
Basically, whenever I try to
Load an employee and
Modify one of the saved TimeEntry, I get that exception.
FYI, I tried replacing the SaveOrUpdate() in the repository for Merge(). It did an excellent job, but when creating an object using Merge(), my object never gets it's Id set.
I also tried creating and flushing the ISession in each function of my repository. It made no sense because as soon as i was trying to load the TimeEntries property of an Employee, an exception was raised, saying the object could not be lazy-loaded as the ISession was closed...
I'm at lost and would appreciate some help. Any suggestion for my repository is also welcome, as i'm quite new to this.
Thanks you guys!
This code
var emp = new Employee(1);
foreach (var timeEntry in emp.TimeEntries)
{
timeEntry.Length += 1;
}
emp.Save();
is creating a new Employee object, presumable with an ID of 1 passed through the constructor. You should be loading the Employee from the database, and your Employee object should not allow the ID to be set since you are using an identity column. Also, a new Employee would not have any TimeEntries and the error message clearly points to an Employee instance as the problem.
I'm not a fan of transactions inside repositories and I'm really not a fan of generic repositories. Why is your EmployeeRepository a generic? Shouldn't it be
public class EmployeeRepository : IRepository<Employee>
I think your code should look something like:
var repository = new EmployeeRepository(session);
var emp = repository.GetById(1);
foreach (var timeEntry in emp.TimeEntries)
{
timeEntry.Length += 1;
}
repository.Save(emp);
Personally I prefer to work directly with the ISession:
using (var txn = _session.BeginTransaction())
{
var emp = _session.Get<Employee>(1);
foreach (var timeEntry in emp.TimeEntries)
{
timeEntry.Length += 1;
}
txn.Commit();
}
This StackOverflow Answer gives an excellent description of using merge.
But...
I believe that you are facing issues with setting up a correct session pattern for your application.
I you suggest to take a look at session-per-request pattern
where in you create a single NHibernate session object per request. the session is opened when the request is received and closed/flushed on generating a response.
Also make sure that instead of using SessionFactory.OpenSession() to get a session try using SessionFactory.GetCurrentSession() which puts the onus on NHibernate to return you the current correct session.
I hope this pushes you in the right direction.

Resources