ASP.NET; Several session variables or a "container object"? - asp.net

I have several variables that I need to send from page to page...
What is the best way to do this?
Just send them one by one:
string var1 = Session["var1"] == null ? "" : Session["var1"].ToString();
int var2 = Session["var2"] == null ? 0 : int.Parse(Session["var2"].ToString());
and so on...
Or put them all in some kind of container-object?
struct SessionData
{
public int Var1 { get; set; }
public string Var2 { get; set; }
public int Var3 { get; set; }
}
--
SessionData data = Session["data"] as SessionData;
What is the best solution? What do you use?

A hybrid of the two is the most maintainable approach. The Session offers a low-impedance, flexible key-value pair store so it would be wasteful not to take advantage of that. However, for complex pieces of data that are always related to each other - for example, a UserProfile - it makes sense to have a deeply nested object.

If all the data that you're storing in the Session is related, then I would suggest consolodating it into a single object like your second example:
public class UserData
{
public string UserName { get; set; }
public string LastPageViewed { get; set; }
public int ParentGroupId { get; set; }
}
And then load everything once and store it for the Session.
However, I would not suggest bundling unrelated Session data into a single object. I would break each seperate group of related items into their own. The result would be something of a middleground between the two hardline approaches you provided.

I use a SessionHandler, which is a custom rolled class that looks like this
public static class SessionHandler
{
public static string UserId
{
get
{
return Session["UserId"];
}
set
{
Session["UserId"] = value;
}
}
}
And then in code I do
var user = myDataContext.Users.Where(u => u.UserId = SessionHandler.UserId).FirstOrDefault();

I don't think I've every created an object just to bundle other objects for storage in a session, so I'd probably go with the first option. That said, if you have such a large number of objects that you need to bundle them up to make it easier to work with, you might want to re-examine your architecture.

I've used both. In general, many session variable names leads to a possibility of collisions, which makes collections a litte more reliable. Make sure the collection content relates to a single responsibility, just as you would for any object. (In fact, business objects make excellent candidates for session objects.)
Two tips:
Define all session names as public static readonly variables, and make it a coding standard to use only these static variables when naming session data.
Second, make sure that every object is marked with the [Serializable] attribute. If you ever need to save session state out-of-process, this is essential.

The big plus of an object: properties are strongly-typed.

Related

Audit.net data models example

Does any one have a working example of how to added audit models to an existing project, for Audit.Net.
It is one fantastic component to use, and up until now, my team and I have gotten by with the standard JSON files, however, we'd like to migrate our current solution to our Xamarin application, and would like to store the auditing in the local SQLite database on the device.
However, the documentation for this project is somewhat lacking and there is no concise examples of how to get custom auditing working with Entity Framework.
We have worked through the MD files on the github repo, but we still cannot get auditing to work.
Another question, similar to this has been asked HERE, but there is no definitive example of what the Audit_{entity} table should look like, what fields it MUST contain, and how to set up relationships for it.
We tried to reverse engineer the JSON files into a relational structure, but at the time of asking this question, we have not gotten any auditing to write to the SQLite database.
Sorry about the documentation not helping too much, hope I (or anybody) can provide better documentation in the future.
I am assuming you are using EntityFramework to map your entities
to a SQLite database, and you want to use the EF data
provider
to store the audits events in the same database, in Audit_{entity} tables.
There is no constraint on the schema you want to use for your Audit_{entity} tables, as long as you have a one-to-one relation between your {entity} table and its Audit_{entity} table. Then the mapping can be configured on several ways.
The recommendation for the Audit_{entity} tables is to have the same columns as the audited {entity} table, with any common additional column needed, like a User and a Date defined on an Interface.
So, if all your Audit_{entity} tables has the same columns/properties as its {entity}, and you added some common columns (defined on an interface), the configuration can be set like this:
public class User
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Audit_User : IAudit
{
public int Id { get; set; }
public string Name { get; set; }
// IAudit members:
public string AuditUser { get; set; }
public datetime AuditDate { get; set; }
public string Action { get; set } // "Insert", "Update" or "Delete"
}
Audit.Core.Configuration.Setup()
.UseEntityFramework(x => x
.AuditTypeNameMapper(typeName => "Audit_" + typeName)
.AuditEntityAction<IAudit>((ev, ent, auditEntity) =>
{
auditEntity.AuditDate = DateTime.UtcNow;
auditEntity.AuditUser = evt.Environment.UserName;
auditEntity.AuditAction = ent.Action;
});
Note the interface is not mandatory, but using it makes the configuration cleaner. Also note you can make your Audit_{entity} inherit from your {entity} if you wanted to.
Update
Maybe my assumption at the beginning is incorrect and you are not auditing EF entities, but any other type of audit. If that's the case, what you are looking for is a Data Provider that stores the audit events into your SQLite database.
At the time being, there is no built-in data provider that stores to SQLite, and if there was one, it would store just the JSON representation of the event in one column (like the SQL/MySql providers). But it looks like you want to have a custom schema, so you will need to implement your own data provider.
Check the documentation here.
Here is a sample skeleton of a data provider:
public class SQLiteDataProvider : AuditDataProvider
{
public override object InsertEvent(AuditEvent auditEvent)
{
// Insert the event into SQLite and return its ID
}
public override void ReplaceEvent(object eventId, AuditEvent auditEvent)
{
// Replace the event given its ID (only used for CreationPolicies InsertOnStartReplaceOnEnd and Manual)
}
// async implementation:
public override async Task<object> InsertEventAsync(AuditEvent auditEvent)
{
// Asynchronously insert the event into SQLite and return its ID
}
public override async Task ReplaceEventAsync(object eventId, AuditEvent auditEvent)
{
// Asynchronously replace the event given its ID
}
}
Then you just set it up with:
Audit.Core.Configuration.Setup()
.UseCustomProvider(new SQLiteDataProvider());

ViewModel type architecture from Controller to View

I have a fairly complex class of Policies, of which I display a checkbox list of them, the user checks which one they want, and returns back to the server via ajax. The class is fairly complex:
public class Policy {
public int PolicyId { get; set; }
public string PolicyName { get; set; }
... another 15 properties ...
}
To display the list of checkboxes I really only need the Id and Name, so I've created a lightweight class PolicyViewModel that is simply:
public class PolicyViewModel {
public int PolicyId { get; set; }
public string PolicyName { get; set; }
}
So I then pass a List to the View and get a List back containing the selected Policies.
Another developer on my team said that he doesn't necessarily want to translate from the ViewModel to the Policy class on the Ajax call to save the selected policies, but I'm resistant to send a List of policies due to how heavy they are to send to the view, retrieving all the properties, etc.
EDIT: For clarification, on the Ajax save method, to persist to the DB, the call needs a list of the full Policy class.
What is the best way to display this list and get back the values? Is there a better way than I am proposing?
Usually, you wouldn't need a separate model when serializing to json. Simply pluck out what you need from the domain object into an anonymous object.
return policies.Select(x => new { PolicyId = x.PolicyId, Name = x.PolicyName});
on the return trip, you shouldn't have to send anything more than the Ids of the policies that the user selected. Those can be easily mapped back to your policy objects.
public Whatever PostPolicyChoices(IEnumerable<int> ids)
{
var checked = _context.Policies.Where(x => returnIds.Contains(x.PolicyId));
// snip
boom. done.
I will recommend you not to work with Domain objects in your mvc application . You must work just with ViewModels, I think this is best practice for mvc projects. Take a look at Automapper and use it in your project, this will simplify your work, so this should look something like this :
in your [HttpGet] method you will have :
var model =Mapper.Map<IList<Policy>,IList<VmSysPolicy>>(yourlist)
And in your [HttpPost] method you will have :
var domainList=Mapper.Map<IList<VmSysPolicy>,IList<Policy>>(modelList);
And in your mapping configuration you will do :
Mapper.CreateMap<Policy,PolicyVmSysPolicy,>()
.ForMemeber()//Your mapping here
and
Mapper.CreateMap<VmSysPolicy,Policy>()
.ForMemeber//mapping here

ASP.NET MVC Entity Framework - Entity Update - Overwriting Database Values with Null Values

I am currently looking for a design pattern or rather a best practice in implementing Repository<Entity>.Update() method for a ASP.NET MVC 4 application which uses Entity Framework 5 with Code First approach.
Problem:
The problem I encountered is that when an entity is queried from the database and shown on a view it may not have all the attributes populated. As a result when the repository.Update(entity) method is invoked, the entity passed to the Update() method may have un-bound properties having null values. However they may have some values in the database. As an example Customer.Misc in below code.
So the problem comes here. According to this approach all the properties which were not bound on the view are set to Null in the database after the first Update() method call.
class Customer
{
public int Id { get; set; }
public string Name { get; set; }
public string Misc { get; set; }
}
[HttpGet]
public ActionResult Update(int id)
{
Repository<Customer> repo = new Repository<Customer>();
return View(repo.GetById(id)); // View only binds Customer.Name
}
[HttpPost]
public ActionResult Update(Customer customer)
{
Repository<Customer> repo = new Repository<Customer>();
repo.Update(customer); // Customer.Misc is null
...
}
public void Update(TEntity entity)
{
var entry = DbContext.Entry<TEntity>(entity);
if (entry.State == EntityState.Detached)
{
ObjectContext.ApplyCurrentValues(EntitySetName, entity);
}
DbContext.SaveChanges();
}
Solutions I could think:
Bind all entity attributes on the view:
I think this is not feasible and at the same time it may lead to performance issues since all attributes get populated.
Implement a custom method to copy property values to avoid null values being copied.
EntityHelper.CopyNotNullValues(source, target) and ignore null values in the source entity. If we do this we might not be able to set any of the values to null if required.
Implement View Models and transform data back and forth with the Domain Model.
This is the best approach I could think of so far. All the attributes bound to the View Model will get populated always, on the Update POST, copy all View Model values to the Domain Model.
Really appreciate your thoughts on this.
In Entity Framework, using ChangeObjectState or ApplyCurrentValues will cause data loss. The only way to work around this issue in this case is attaching the input entity and mark the properties to be updated. See below example:
public void Update(TEntity entity, string[] updatedProperties)
{
DbContext.Entities.Attach(entity);
var entry = DbContext.Entry<TEntity>(entity);
for (int i = 0; i < updatedProperties.Length; i++)
{
entry.SetModifiedProperty(updatedProperties[i]);
}
DbContext.SaveChanges();
}
[HttpPost]
public ActionResult Update(Customer customer)
{
Repository<Customer> repo = new Repository<Customer>();
repo.Update(customer, new string[]{ "Name" }); // Only update name
...
}
It's the best solution I can think of. You wanna have least code and good performance. It's as difficult as finding an easy and well paid job.

Need help rewriting this Linq query to move it from code-behind to DAL as reusable object

I'm working to move my simple asp.net website to a three layer architecture. Currently I have Linq queries like the one below in my code-behind files. Basically this code snippet retrieves a collection of customer data from the database and then binds it to a grid control.
I'm wondering if someone can guide me on how to rewrite this in order to move it to my newly-created data access layer. I'm thinking I will turn it into a class (e.g. GetUserBoxesByStatus()) that can be reused throughout the site.
var boxes = from p in sbm.Packages
where p.UserID == CurrentUserId && p.StatusID > 1 && p.StatusID < 3
select new { p.PackageTag, p.PackageName, p.DateReceived, p.DateShipped };
GridView1.DataSource = boxes;
DataBind();
Some of the options that I've investigated but have not had success implementing are the following:
DataTable --- returning a DataTable seems like the best solution but it also appears to require a lot of potentially unecessarry code to define a table (isn't the data source already mapped in my Linq 2 Entities dbml?)
IEneuerable --- I think I could pass an IEnumerable list between the layers but after reading many tutorials about Linq I'm still a little lost
DTO --- Conceptually I think I understand what a DTO is but I am not clear on how to begin implementing this approach
POCO --- Again, the concept seems logical enough but I don't know how to put this into practice
I'm hoping someone here can look at my code example and propose how they would tackle this using one of the above or some other solution.
Create a class with the properties you need. Select into that class. Return a strongly-typed List (so that the query is actually performed in the DAL, not in your view). Bind your data source to the list.
public class PackageViewModel
{
public string Tag { get; set; }
public string Name { get; set; }
public DateTime Received { get; set; }
public DateTime Shipped { get; set; }
}
DAL
public List<PackageViewModel> GetUserBoxesByStatus( int userID, int minStatus, int maxStatus )
{
return sbm.Packages
.Where( p => p.UserID == userID
&& p.StatusID > minStatus
&& p.StatusID < maxStatus )
.Select( p => new PackageViewModel
{
Tag = p.PackageTag,
Name = p.PackageName,
Received = p.DateReceived,
Shipped = p.DateShipped
})
.ToList();
}

Factory pattern to "set" product in addition to "get" product?

I am new to design patterns. I am looking for a pattern similar to the factory pattern but that will also let me "set" the product. Something like this:
class VehicleFactory
{
IVehicle static GetVehicle();
void static SetVehicle(IVehicle vehicle);
}
Is there any known pattern similar to this? Thank you.
EDIT: I am looking to store "POCO" objects in the Session object and use a class to set/ get them. I may want to switch persistance to ViewState/ database in the future. This is what I have:
// object to persist in Session.
class Vehicle
{
string Make { get; set; }
string Model { get; set; }
}
// class to set/ get object from Session.
// Please see VehicleFactory above.
Factory pattern is a creational design pattern with encapsulates the creation of a complex object and isolates the creation process from your business logic.
Here it looks like you want a cache to store and manage the Vehicle instances. I would recommend that you call this class a VehicleCache rather than Factory and implement like a cache.
Firstly you should consider having and identifier for the Vehicle object like a vehicleId. I would also recommend that you implement it as an entity object as described in Domain Driven Design.
Then you can implement your cache like this -
public class VehicleCache
{
public void Add(IVehicle instanceToAdd)
{
// Store instance in session object
}
public IVehicle Get(string id)
{
// search and return vehicle from cache
}
// more methods and indexer if required
}
Here are some links that explain how you can implement such cache for your application in a thread safe fashion -
https://blogs.infosupport.com/blogs/frankb/archive/2008/12/31/Implementing-a-Thread-Safe-cache-using-the-Parallel-Extensions.aspx
http://www.objectreference.net/post/Implementing-Generic-Caching.aspx
Like Unmesh says, the name is kind of misleading.
You simply want to cache IVehicle object.
IVehicleCache
{
IVehicle GetVehicle();
void SetVehicle(IVehicle vehicle);
}
// Implementation for http session
public class HttpSessionVehicleCache : IVehicleCache
{
public IVehicle GetVehicle()
{
return (IVehicle)HttpContext.Current.Session["Vehicle"];
}
void SetVehicle(IVehicle vehicle)
{
HttpContext.Current.Session["Vehicle"] = vehicle;
}
}

Resources