Global class variable for ASP.NET - c#

I am building an ASP.NET Application which has 2 projects.
One is a class library having BL Code.
I want to create a public class instance variable from one of the classes in BL.
This class instance variable is to avoid loading all the data on each request which makes my application to respond slow for each request.
How to make the global class variable load data at page_Load, and keep it until the user redirects to another page.

Create it in ViewState and wrap it in a property for easy of use. Something along the lines of:
public MyClass MyObj {
get {
if (ViewState["MyObj"] == null){
ViewState["MyObj"] = new MyClass();
}
return ViewState["MyObj"];
}
set {
ViewState["MyObj"] = value;
}
}

Related

How can I unit test, that one viewmodel sends to another viewmodel proper string?

In a view model's constructor I have a command declaration that calls a method:
OpenGroupCommand = new DelegateCommand(OnOpenGroupExecute);
And the method looks like:
private void OnOpenGroupExecute(object obj)
{
string groupName = (string)obj;
Application.Current.MainPage.Navigation.PushAsync(new GroupPage(groupName));
}
How can I test, that groupName is passed to another view model correctly? In another view model groupName parameter is sent to GroupName property on VM instance:
public class GroupPageViewModel : ViewModelBase, IGroupPageViewModel
{
private string _groupName;
public GroupPageViewModel(string groupName)
{
LoadGroupName(groupName);
}
public void LoadGroupName(string groupName)
{
GroupName = groupName;
}
public string GroupName
{
get
{
return _groupName;
}
set
{
_groupName = value;
OnPropertyChanged();
}
}
}
On debug all works fine, but how can I unit test it? Where can I read a bit about testing and mocking stuff like this, even with Moq framework?
I believe your question is actually about how to test navigation between pages.
In the implementation of method OnOpenGroupExecute, because you are using Xamarin forms stuff to implement the navigation, you have to refer Xamarin Forms assemblies in your test project which makes the unit test depend on Xamarin Forms.
As suggested in this document https://learn.microsoft.com/en-us/xamarin/xamarin-forms/enterprise-application-patterns/ , try to create an interface for navigation and navigate with viewmodel (more details on https://github.com/dotnet-architecture/eShopOnContainers)
And in your unit test project, implement a fake navigation service class like below and inject into the DI container:
public class FakeNavigationService : INavigationService //this interface is from MS eShopOnContainer project
{
private List<ViewModelBase> _viewModels = new List<ViewModel>();
public Task NavigateToAsync<TViewModel>() where TViewModel : ViewModelBase {
//create viewModel object from DI container
//var viewModel = ......
_viewModels.Add(viewModel);
}
public ViewModelBase CurrentPageViewModel {
get {
if (_viewModels.Count() < 1) {
return null;
}
return _viewModels[_viewModels.Count() - 1];
}
}
}
This is just a suggestion. If you have implemented most of features in your app, it takes time to change navigate-with-page to navigate-with-viewmodel.
Well, let's see what you have:
you have some code in a private method, unless you make that public you won't be able to test it directly, because you can't call it. I am not considering here any tricks that allow you to call private methods.
what does that method do? It is not clear at all, it receives an object, we don't know what's in it. You're converting it to string, but what if it is not a string? Can you convert that object to a string? who knows.
So we have a method, that we don't know what it does, we don't know what it receives as parameters, we can't call it directly, but we want to test it. This is not a good position to be in.
Step back a bit and ask yourself, what are you really trying to test?
You said : How can I test, that groupName is passed to another view model correctly?
what does "correctly" mean? You need to define what it means for that string to be correct. This will give a test scenario you can work with.
I expect to receive an object, which looks like A and I want to convert it to a string which looks like B. Forget about viewmodels for now, that's just unimportant noise.
You can change the method into a public one and you can test that for different types of input data, you're getting the right result. This is literally, working with an object and extract some stuff from it. When that method is correct, you can guarantee that the viewmodel will receive the right input and that is good enough from a unit testing point of view.
You can of course add more tests for various inputs, you can test for correct failure conditions etc.

How to get a mock repository into a model object

I am creating some unit tests for a Country model object. This is partly-generated by the Linq-to-SQL mechanism from a database table and partly under my control. This class uses the CountryRepository for some checks when checking it is valid; particularly that a country of this name doesn't already exist in the database.
As one ought not to embroil oneself in the database during unit tests, I created a mock repository to provide pretend data, and modify the model class like this:-
public partial class Country
{
private ICountryRepository country_repository;
public Country(ICountryRepository passed_country_repository)
{
country_repository = passed_country_repository;
}
//...etc
I can then construct this object in the test like this:-
Country test_country = new Country(new MockCountryRepository())
{
// code in here
};
and the tests run satisfactorily.
The problem comes in actual live usage; I have to prefix every usage of the repository with this:-
if (country_repository == null)
{
country_repository = new CountryRepository();
}
as the country_repository variable is unset if the zero-parameter constructor is invoked. I originally had the declaration line reading:-
private ICountryRepository country_repository = new CountryRepository();
but that attempts a database connection whichever constructor is used. I can't change the zero-parameter constructor to set country_repository to anything because it is automatically-generated and my changes might disappear at zero notice.
Is there a better way of getting the MockCountryRepository into the model object? Or have I missed the point here somewhere, and if so, what should I be doing?

How to combine database access and cache in asp.net mvc (An object reference is required for the non-static field, method, or property 'Module.dbApp')

This is actually 2 questions in one.
I have an asp.net mvc application where I have to load a list of Modules, its just a simple list with ID, modulename and a class name to render it on the view with font awesome.
My model is like this:
public class Module
{
[Key]
public int Id { get; set; }
public string ModuleName { get; set; }
public string FontAwesomeClass { get; set; }
}
Because the module list is a Partial View that will render some icons on the top navigation bar, I dont want that for each refresh of the app, it goes to the DB, so it must be cached(I am using Azure REDIS Cache, not relevant for the question anyway), so instead of calling the DB context directly from the controller, I am calling a Cache Class that will check if the cache object exists, if not it will retrieve it from DB, if it does, it will return it from cache.
This my solution structure:
http://screencast.com/t/uayPYiHaPCav
Here is my controller Module.cs
public ActionResult GetModules()
{
return View(Cache.Module.GetModules());
}
As you can see the Controller does not have any logic where to get the data from.
Here is the Module.cs (on the Cache Namespace)
public class Module
{
private AppDataContext dbApp = new AppDataContext();
//Load modules from cache or from database
public static List<Models.Module> GetModules()
{
IDatabase cache = Helper.Connection.GetDatabase();
List<Models.Module> listOfModules = (List<Models.Module>)cache.Get("Modules");
if (listOfModules == null)
{
return dbApp.ModuleList.ToList();
}
else
{
return listOfModules;
}
}
}
Here I have a compiler error which I am not sure how to best fix it:
Error CS0120 An object reference is required for the non-static field,
method, or property 'Module.dbApp'
So that was my first question.
The 2nd question is more about the design pattern, do you consider this correct or not? the way I am trying to get the data from Cache, and its actually the Cache class which checks if data is on it or if it has to go to the DB.
First Question: make your private member static
private static AppDataContext dbApp = new AppDataContext();
2nd Question: your cache strategy seems pretty standard. The only thing is that you might want to expire cache data. For example, the cached data can get old and the longer it stays in the cache the older it gets. You might at some point want to expire it and get fresh data again.
Update:
#EstebanV for code sample (this off the top of my head, don't assume that it compiles):
/**
ICachedPersonDao abstracts away the caching mechanism
away from the core of your application
**/
public CachedPersonDao : ICachedPersonDao
{
private IPersonDao personDao = null;
public CachedPersonDao(IPersonDao personDao)
{
this.personDao = personDao;
}
public Person GetPersonById(int id){
bool isInCache = CACHE.SomeFunctionThatChecksInYourCache(id);
if (isInCache)
{
return CACHE.SomeFunctionThatReturnsTheCachedPerson(id);
}
else
{
//Well it's not in the cache so let's get it from the DB.
return this.personDao.GetPersonById(id);
}
}
}
/**
IPersonDao abstracts database communication
away from the core of your application
**/
public class PersonDao : IPersonDao
{
public Person GetPersonById(int id)
{
/** Get the person by id from the DB
through EntityFramework or whatever
**/
}
}
Usage:
In your controller, use ICachedPersonDao if you want to attempt to get from cache or use IPersonDao if you want to get it directly from the database without checking the cache.
Like I said, you should learn Dependency Injection it will help "inject" these dependencies into the classes that uses them.
I say again, this is off the top of my head. It won't compile. It's just to illustrate the concept.

How to make Business layer object create many instances of the same Data Access layer object

Until now by Business Layer was instantiating one instance of my needed DAL objects:
public class BarcodeBLL : IBarcodeBLL
{
private BarcodeConfig _MyConfig;
private readonly IJDE8Dal _JDE8dal;
private readonly IBarcodeDal _barcodeDal;
public BarcodeBLL(BarcodeConfig MyConfig, ERPConfig erpConfig, BarcodeDALConfig barcodeDalConfig)
{
_MyConfig = MyConfig;
_JDE8dal = new JDE8Dal(erpConfig);
_barcodeDal = new BarcodeDAL(barcodeDalConfig);
}
...
...
}
A new set of front end applications need to access data on 4 different servers (SAME Data Access Layer implementation with 4 different connectionstrings).
One way is to let Ui instantiate 4 BarcodeBLL objects and do the job which i dont want in any case , because i would transfer business logic to UI.
So i have to find a proper way of instantiating from 1 to 4 DAL instances according to the UI application.
One thought is to pass a List<ERPConfig> and/or a List<BarcodeDALConfig> and let somewhow the contructor (???) decide what to do..
I started doing it like this:
public partial class BusinessLayer
{
private readonly Dictionary<string,IJDE8Dal> _JDE8dals;
public BusinessLayer(Dictionary<string,JDEDalConfig> jdeConfigs)
{
foreach (var j in jdeConfigs)
{
_JDE8dals.Add(j.Key,new JDE8Dal(j.Value));
}
}
}
This is what i am looking for..
Additional Info for clarity:
My goal as i see it now is for ONE method in BLL to be able to get from 1 to 4 DAL objects and execute methods in each of them.
Possible scenarions:
UI asks from BLL method GetItemList data from 2 countries.
Bll must unserstand somehow to create 2 DAL objects withg the correct connectionstring and do its job.
So i am consolidating operations for all my servers in the BLL and letting DAL to be alone.
Create an Enum, and modify your constructor to take a variable of the Enum?
Catch the incoming enum in init, and set a private property/variable.
Then inside your class, access the correct DAL based on the current selected enum.
from Business Layer
Dim d as new DAL(option1)
or
Dim d as new DAL(option2)
The solution i followed is this:
public partial class BusinessLayer
{
private readonly Dictionary<string,IJDE8Dal> _JDE8dals;
public BusinessLayer(Dictionary<string,JDEDalConfig> jdeConfigs)
{
foreach (var j in jdeConfigs)
{
_JDE8dals.Add(j.Key,new JDE8Dal(j.Value));
}
}
}
So the BLL layer will accept a dictionary of variable number of entries.
UI Application will be responsible to sent the dictionary so it is its own decision of how many DALs will be instantiated.
Moreover, BLL methods will be responsible to check for the existence of dictionary entries and act accordingly.

How to access session variables from any class in ASP.NET?

I have created a class file in the App_Code folder in my application. I have a session variable
Session["loginId"]
I want to access this session variables in my class, but when I am writing the following line then it gives error
Session["loginId"]
Can anyone tell me how to access session variables within a class which is created in app_code folder in ASP.NET 2.0 (C#)
(Updated for completeness)
You can access session variables from any page or control using Session["loginId"] and from any class (e.g. from inside a class library), using System.Web.HttpContext.Current.Session["loginId"].
But please read on for my original answer...
I always use a wrapper class around the ASP.NET session to simplify access to session variables:
public class MySession
{
// private constructor
private MySession()
{
Property1 = "default value";
}
// Gets the current session.
public static MySession Current
{
get
{
MySession session =
(MySession)HttpContext.Current.Session["__MySession__"];
if (session == null)
{
session = new MySession();
HttpContext.Current.Session["__MySession__"] = session;
}
return session;
}
}
// **** add your session properties here, e.g like this:
public string Property1 { get; set; }
public DateTime MyDate { get; set; }
public int LoginId { get; set; }
}
This class stores one instance of itself in the ASP.NET session and allows you to access your session properties in a type-safe way from any class, e.g like this:
int loginId = MySession.Current.LoginId;
string property1 = MySession.Current.Property1;
MySession.Current.Property1 = newValue;
DateTime myDate = MySession.Current.MyDate;
MySession.Current.MyDate = DateTime.Now;
This approach has several advantages:
it saves you from a lot of type-casting
you don't have to use hard-coded session keys throughout your application (e.g. Session["loginId"]
you can document your session items by adding XML doc comments on the properties of MySession
you can initialize your session variables with default values (e.g. assuring they are not null)
Access the Session via the thread's HttpContext:-
HttpContext.Current.Session["loginId"]
The problem with the solution suggested is that it can break some performance features built into the SessionState if you are using an out-of-process session storage. (either "State Server Mode" or "SQL Server Mode"). In oop modes the session data needs to be serialized at the end of the page request and deserialized at the beginning of the page request, which can be costly. To improve the performance the SessionState attempts to only deserialize what is needed by only deserialize variable when it is accessed the first time, and it only re-serializes and replaces variable which were changed. If you have alot of session variable and shove them all into one class essentially everything in your session will be deserialized on every page request that uses session and everything will need to be serialized again even if only 1 property changed becuase the class changed. Just something to consider if your using alot of session and an oop mode.
The answers presented before mine provide apt solutions to the problem, however, I feel that it is important to understand why this error results:
The Session property of the Page returns an instance of type HttpSessionState relative to that particular request. Page.Session is actually equivalent to calling Page.Context.Session.
MSDN explains how this is possible:
Because ASP.NET pages contain a default reference to the System.Web namespace (which contains the HttpContext class), you can reference the members of HttpContext on an .aspx page without the fully qualified class reference to HttpContext.
However, When you try to access this property within a class in App_Code, the property will not be available to you unless your class derives from the Page Class.
My solution to this oft-encountered scenario is that I never pass page objects to classes. I would rather extract the required objects from the page Session and pass them to the Class in the form of a name-value collection / Array / List, depending on the case.
In asp.net core this works differerently:
public class SomeOtherClass
{
private readonly IHttpContextAccessor _httpContextAccessor;
private ISession _session => _httpContextAccessor.HttpContext.Session;
public SomeOtherClass(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
public void TestSet()
{
_session.SetString("Test", "Ben Rules!");
}
public void TestGet()
{
var message = _session.GetString("Test");
}
}
Source: https://benjii.me/2016/07/using-sessions-and-httpcontext-in-aspnetcore-and-mvc-core/
I had the same error, because I was trying to manipulate session variables inside a custom Session class.
I had to pass the current context (system.web.httpcontext.current) into the class, and then everything worked out fine.
MA
This should be more efficient both for the application and also for the developer.
Add the following class to your web project:
/// <summary>
/// This holds all of the session variables for the site.
/// </summary>
public class SessionCentralized
{
protected internal static void Save<T>(string sessionName, T value)
{
HttpContext.Current.Session[sessionName] = value;
}
protected internal static T Get<T>(string sessionName)
{
return (T)HttpContext.Current.Session[sessionName];
}
public static int? WhatEverSessionVariableYouWantToHold
{
get
{
return Get<int?>(nameof(WhatEverSessionVariableYouWantToHold));
}
set
{
Save(nameof(WhatEverSessionVariableYouWantToHold), value);
}
}
}
Here is the implementation:
SessionCentralized.WhatEverSessionVariableYouWantToHold = id;

Categories

Resources