How does the session state work in MVC 2.0? - asp.net-mvc-2

I have a controller that stores various info (Ie. FormID, QuestionAnswerList, etc). Currently I am storing them in the Controller.Session and it works fine.
I wanted to break out some logic into a separate class (Ie. RulesController), where I could perform certain checks, etc, but when I try and reference the Session there, it is null. It's clear that the Session remains valid only within the context of the specific controller, but what is everyone doing regarding this?
I would imagine this is pretty common, you want to share certain "global" variables within the different controllers, what is best practice?
Here is a portion of my code:
In my BaseController class:
public List<QuestionAnswer> QuestionAnswers
{
get
{
if (Session["QuestionAnswers"] == null)
{
List<QuestionAnswer> qAnswers = qaRepository.GetQuestionAnswers(CurrentSection, UserSmartFormID);
Session["QuestionAnswers"] = qAnswers;
return qAnswers;
}
else
{
return (List<QuestionAnswer>)Session["QuestionAnswers"];
}
}
set
{
Session["QuestionAnswers"] = value;
}
}
In my first Controller (derived from BaseController):
QuestionAnswers = qaRepository.GetQuestionAnswers(CurrentSection, UserSmartFormID);
I stepped through the code and the above statement executes fine, setting the Session["QuestionAnswers"], but then when I try to get from another controller below, the Session["QuestionAnswers"] is null!
My second controller (also derived from BaseController):
List<QuestionAnswer> currentList = (List<QuestionAnswer>)QuestionAnswers;
The above line fails! It looks like the Session object itself is null (not just Session["QuestionAnswers"])

does it make a difference if you retrieve your session using
HttpContext.Current.Session("mySpecialSession") ''# note this is VB, not C#

I believe TempData will solve your problem, it operates with in the session and persists across multiple requests, however by default it will clear the stored data once you access it again, if that's a problem you can tell it to keep the info with the newly added Keep() function.
So in your case:
...
TempData["QuestionAnswers"] = qAnswers;
...
There's much more info at:
http://weblogs.asp.net/jacqueseloff/archive/2009/11/17/tempdata-improvements.aspx

Where are you accessing the session in the second controller? The session object is not available in the constructor because it is injected later on in the lifecycle.

Ok, finally got it working, although a bit kludgy. I found the solution from another related SO post.
I added the following to my BaseController:
public new HttpContextBase HttpContext
{
get
{
HttpContextWrapper context =
new HttpContextWrapper(System.Web.HttpContext.Current);
return (HttpContextBase)context;
}
}
Then set/retrieved my Session variables using HttpContext.Session and works fine!

Related

Reading attributes from private key

I'm trying to use Pkcs11Interop to sign a message using the private key from a smart card certificate in a C# application. The smart card we are using contain multiple certificates - usually one is for signing, and one is for authentication. If I were using X509Certificate2, I'd filter certificates based on the X509KeyUsageFlags I'm looking for. I'm struggling to figure out how to approach this using PKCS11.
The code I'm starting with is below. When I call session.FindAllObjects, I'm getting 2 certificates in the result (which is expected, since that is how many certificates are on the smart card.)
I've tried using GetAttributeValue to read various attributes and see if I can use those to identify the correct certificate - strangely, they all return null/0 values. Querying the CKA_SENSITIVE attribute returns True (which is, again, expected), but apparently I cannot read other attributes from the objects.
Am I doing something incorrect in my usage of GetAttributeValue? Or is there some other way I should be approaching this problem?
public byte[] SignMessage(byte[] message, string pin)
{
var factories = new Pkcs11InteropFactories();
using (IPkcs11Library pkcs11Library = factories.Pkcs11LibraryFactory.LoadPkcs11Library(factories, DriverPath, AppType.SingleThreaded))
{
ISlot slot = GetSlot(pkcs11Library);
if (slot == null)
{
return null;
}
using (ISession session = slot.OpenSession(SessionType.ReadWrite))
{
session.Login(CKU.CKU_USER, pin);
var searchTemplate = new List<IObjectAttribute> {
factories.ObjectAttributeFactory.Create(CKA.CKA_CLASS, CKO.CKO_PRIVATE_KEY),
factories.ObjectAttributeFactory.Create(CKA.CKA_KEY_TYPE, CKK.CKK_RSA),
factories.ObjectAttributeFactory.Create(CKA.CKA_SIGN, true),
};
List<IObjectHandle> foundObjects = session.FindAllObjects(searchTemplate); // foundObjects.Count = 2!
IObjectHandle privateKey = foundObjects.FirstOrDefault();
var readResult = session.GetAttributeValue(privateKey, new List<CKA>() { CKA.CKA_LABEL });
var label = readResult[0].GetValueAsString(); // label ends up being null!
byte[] result = null;
using (IMechanism signingMechanism = session.Factories.MechanismFactory.Create(CKM.CKM_SHA256_RSA_PKCS))
{
result = session.Sign(signingMechanism, privateKey, message);
}
session.DestroyObject(privateKey);
session.Logout();
return result;
}
}
}
I came up with a solution through trial-and-error that seems to function correctly. I'm not sure if this is the correct approach, since it seems quite convoluted, so any feedback would be appreciated. I discovered that the contents of the card include a variety of objects, and a single key pair consists of three objects: a CKO_CERTIFICATE object (which seems to contain the brunt of the metadata about the certificate/keypair), a CKO_PRIVATE_KEY object and a CKO_PUBLIC_KEY object. Each of these has the CKA_ID property populated, and the objects that are part of the same key pair should have the same CKA_ID.
So I built a CertificateWrapper wrapper class to hold references to each of the three objects. I then looped over all objects on the smart card, and built CertificateWrapper objects for each unique key pair.
Then, I was able to construct an X509Certificate2 object using the CKA_VALUE attribute on the CKO_CERTIFICATE object. From there, I was able to build a X509Certificate2Collection object using an array of all of the X509Certificate2 objects I made. I could then use the .Find method (or any other method I wanted) on X509Certificate2Collection to filter down to the particular certificate I was looking for.
Once I had the X509Certificate2 object I was looking for, I was able to map it back to the CertificateWrapper object by matching the serial number from the X509Certificate2 against the CKA_SERIAL_NUMBER attribute from the CKO_CERTIFICATE object. Finally, I was able to use the CKO_PRIVATE_KEY object associated with that CKO_CERTIFICATE to do the signing operation.
Like I said, this seems very round-about, but seemed to allow me to find the correct certificate/key pair I needed for my specific workflow. Hope this explanation might be useful to someone, and I also welcome any feedback on problems with this approach and/or better ways to handle this.

kotlin coroutine - what is default scope?

How does coroutines default scope work if i do not specify anything. lets take a look at this example:
class MyAppCompatActivity:AppCompatActivity{
fun getContact() {
GlobalScope.launch {
val contact = contacts.getContact() // suspended function
withContext(Dispatchers.Default) {
phoneContact.value = contact }
}
}
}
which simply updates the UI when a contact is retrieved. this is added to the global scope of so the coroutine life span can be that of the entire application.
but lets do the same thing again without a globalScope:
class MyAppCompatActivity:AppCompatActivity{
fun getContact() {
launch {
val contact = contacts.getContact() // suspended function
withContext(Dispatchers.Default) {
phoneContact.value = contact }
}
}
}
what is the lifespan of getContact now that i have removed the globalScope ? is it tied to the MyAppCompatActivity scope ?
Your code will fail to compile because launch must be called on a CoroutineScope object. This object specifies the lifespan of the coroutine. Since your activity does not implement a scope it will fail to compile or call a completely unrelated launch function.
I don't think this is a good idea anymore, as it looks like they're just functions for testing (doesn't launch coroutines). Maybe this was an API available previously, but now you should be using lifecycleScope to scope a coroutine to a fragment or activity, and viewModelScope to scope them to a View Model's life cycle. These are properties available in those classes by already.
Here's what I see when I try to use launch:

FluentMongo throwing error all of a sudden

I am using FluentMongo and the MongoDBCSharpDriver. My code was working fine for a while, but after updating my MongoCSharpDriver, I now I keep getting this error when I try to query the database:
"Discriminators can only be registered for classes, not for interface MyLib.Services.IRepoData."
The interface IRepoData is just one that I use for all my objects saved to MongoDB. It just defines _id for everything. Here is the line that is breaking:
var item = Collection.AsQueryable().SingleOrDefault(a => a.Id == itemID);
Can anyone shed some light on this one? If I just use .SingleOrDefault() with no lambda then it works fine, its passing a lambda that breaks it.
EDIT
In case this helps...
var Collection = GetCollection<MyClass>();
private MongoCollection<T> GetCollection<T>() where T : class, new()
{
string typeName = typeof(T).Name;
var collection = db.GetCollection<T>(typeName, safeMode);
return collection;
}
Found it! I was calling GetCollection() from within another generic method, like this:
public T Save<T>(T item) where T : class, IRepoData, new()
{
GetCollection<T>().Save(item);
}
This caused GetCollection to see T as the interface instead of the actual instance class. GetCollection works fine anywhere else.
For anyone else with this problem, I just used a low level query like this instead... Collection.FindOneAs<T>(Query.EQ("Id", itemID.ToString()));

NullReferenceException while trying to including a one-to-many relationship item after saving parent

Framework: I'm using using MVC 3 + EntityFramework 4.1 Code-First.
Concept: One Legislation entity has many Provision entities. The idea is that the user enters a Legislation entity, that gets saved then the function that saves it passes it along to another function to see whether that Legislation has a ShortTitle. If it does, then it formats it into a properly worded string and includes it as the Legislation's first Provision, then saves the changes to db.
Issue: The problem is, I've tried coding it in different ways, I keep getting a NullReferenceException, telling me to create a new object instance with the "new" keyword, and points me to the savedLegislation.Provisions.Add(provision); line in my second function.
Here are the two functions at issue, this first one saves the Legislation proper:
public Legislation Save(NewLegislationView legislation)
{
Legislation newLegislation = new Legislation();
// Simple transfers
newLegislation.ShortTile = legislation.ShortTile;
newLegislation.LongTitle = legislation.LongTitle;
newLegislation.BillType = legislation.BillType;
newLegislation.OriginatingChamber = legislation.OriginatingChamber;
newLegislation.Preamble = legislation.Preamble;
// More complicated properties
newLegislation.Stage = 1;
this.NumberBill(newLegislation); // Provides bill number
newLegislation.Parliament = db.LegislativeSessions.First(p => p.Ending >= DateTime.Today);
newLegislation.Sponsor = db.Members.Single(m => m.Username == HttpContext.Current.User.Identity.Name);
// And save
db.Legislations.Add(newLegislation);
db.SaveChanges();
// Check for Short titles
this.IncludeShortTitle(newLegislation);
// return the saved legislation
return newLegislation;
}
And the second function which is invoked by the first one deals with checking whether ShortTitle is not empty and create a Provision that is related to that Legislation, then save changes.
public void IncludeShortTitle(Legislation legislation)
{
var savedLegislation = db.Legislations.Find(legislation.LegislationID);
if (savedLegislation.ShortTile.Any() && savedLegislation.ShortTile.ToString().Length >= 5)
{
string shortTitle = "This Act may be cited as the <i>" + savedLegislation.ShortTile.ToString() + "</i>.";
var provision = new Provision()
{
Article = Numbers.CountOrNull(savedLegislation.Provisions) + 1,
Proponent = savedLegislation.Sponsor,
Text = shortTitle
};
savedLegislation.Provisions.Add(provision);
db.SaveChanges();
}
}
I've been researching how SaveChanges() works and whether it is properly returning the updated entity, it does (since I get no issue looking it up in the second function). If it works properly, and the legislation is found and the provision is newly created in the second function, I don't see what is the "null" reference it keeps spitting out.
The null reference in this case would be savedLegislation.Provisions. The Provisions collection won't be initialized to a new List<Provision> when EF returns your Legislation instance from the db.Legislations.Find(...) method.
The first thing I'd try is something like this:
var savedLegislation = db.Legislations
.Include("Provisions")
.First(l => l.LegislationID == legislation.LegislationID);
... but I'd also consider just using the legislation instance that was passed into the method rather than fetching it from the database again.

return statement from within using

using (IDbCommand command = new SqlCommand())
{
IDbDataAdapter adapter = new SqlDataAdapter();
DataSet ds = new DataSet();
adapter.SelectCommand = command;
command.Connection = _dataAccess.Connection;
command.CommandType = CommandType.StoredProcedure;
command.CommandText = "GetProcData";
command.Parameters.Add(new SqlParameter("#ProcID ", procId));
adapter.Fill(ds);
return ds.Tables[0].AsEnumerable();
}
This returns an IEnumerable DataRow The question is that since the return is within the using statement, will it property dispose of the IDBCommand? I know I can easily refactor this so I change the scope of the DataSet outside of the using, but it is more of a wonder than anything else.
Yes, this will work as expected with IDbCommand being properly disposed. The compiler will transform the using block to a try-catch-finally, where Dispose is invoked in the finally block.
Yes, the DB Command will be disposed, so far so good.
You can get troubles with IEnumerables. Because the items could potentially be produced when getting them from the IEnumerable, not when creating the IEnumerable, that is the nature of it. So it depends on how ds.Tables[0].AsEnumerable() is implemented. It could wait with executing the command until you get the first item. This is in the calling code, outside of the using block. You'll get an error, because the command had been disposed.
This is probably not an issue here, but should always be considered when returning IEnumerables (or lambda expressions) from a using block:
using (A a = new A())
{
return someItems.Select(x => a.Get(x));
}
When accessing the first item, a is already disposed and you get an error.
The IDbCommand is disposed correctly. As a rule of thumb when returning from within a using statement you are fine to do so so long as:
The thing you are returning isn't in the clause of the using
statement
The thing being returned isn't a reference created within the block of the using statement.
In the first case the using statement will dispose of the thing you are trying to return and in the second case the variable will go out of scope.
e.g.
//this is fine as result is createsd outside the scope of the block.
bool result = false;
using (SmtpClient mailClient = new SmtpClient())
{
try
{
mailClient.Send(...);
result = true;
}
catch(SmtpException)
{
result = false;
}
finally
{
return result;
}
}
Here, the using(){ ... } statement is our friend. When we exit the block our SmtpClient is disposed, and the result condition will still exist for you to use.
However, say we are writing a WinForm app or WPF app and we wrap a using block around our data context then we create a problem as the context disappears before the control can consume it.
// this will fail when you bind the customers to a form control!
using (DbContext context = new DBContext())
{
context.Customers.Where(c => c.Name.Contains("Bob")).Load();
return context.Customers.Local;
}
Here, the using(){ ... } statement hurts us. As when we come to dataBind our customer to a GridView (or other such databound control) the fact that we have disposed of the DbContext will mean our form has nothing to bind to so it will throw an exception!
HTH
The scope of your IDbCommand object is very clear: between the brackets { and }. As soon as your program flow exits from there, the object is disposed.