I am creating a helper class for my MVC application. This class will contain static methods that will pull information the first time the user logs into the system.
I have created two methods that will return lists like list of countries and list of languages. I don't want to execute this every time but save results of first call and return it for subsequent calls.
public static List<Languages> GetLanguages()
{
using (var db = new MCREntities())
{
var languages = db.spGetLanguages(0);
return Mapper.Map<List<Languages>>(languages);
}
}
public static List<Countries> GetCountries()
{
using (var db = new MCREntities())
{
var countries = db.spGetAllCountries("");
return Mapper.Map<List<Countries>>(countries);
}
}
Inside your class you can have static list which would hold Languages anly first time would try to access database.
private static List<Languages> _languages = null;
public static List<Languages> GetLanguages()
{
if(_languages == null){
using (var db = new MCREntities())
{
var languages = db.spGetLanguages(0);
_languages = Mapper.Map<List<Languages>>(languages);
}
}
return _languages;
}
Alternatively, you can implement cache
i would say create a class with the required properties liek
public static class CurrentSession{
List<Languages> lang{get;set;}
List<Countries> countries{get;set;}
}
and in global.asax file
protected void Application_Start()
{
//.........predefined codes
CurrentSession.lang = GetLanguages();
CurrentSession.Countries =GetCountries();
Related
As a caveat I'm a novice with Rx (2 weeks) and have been experimenting with using Rx, RxUI and Roland Pheasant's DynamicData.
I have a service that initially loads data from local persistence and then, upon some user (or system) instruction will contact the server (TriggerServer in the example) to get additional or replacement data. The solution I've come up with uses a Subject and I've come across many a site discussing the pros/cons of using them. Although I understand the basics of hot/cold it's all based on reading rather than real world.
So, using the below as a simplified version, is this 'right' way of going about this problem or is there something I haven't properly understood somewhere?
NB: I'm not sure how important it is, but the actual code is taken from a Xamarin.Forms app, that uses RxUI, the user input being a ReactiveCommand.
Example:
using DynamicData;
using System;
using System.Linq;
using System.Reactive;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using System.Threading.Tasks;
public class MyService : IDisposable
{
private CompositeDisposable _cleanup;
private Subject<Unit> _serverSubject = new Subject<Unit>();
public MyService()
{
var data = Initialise().Publish();
AllData = data.AsObservableCache();
_cleanup = new CompositeDisposable(AllData, data.Connect());
}
public IObservableCache<MyData, Guid> AllData { get; }
public void TriggerServer()
{
// This is what I'm not sure about...
_serverSubject.OnNext(Unit.Default);
}
private IObservable<IChangeSet<MyData, Guid>> Initialise()
{
return ObservableChangeSet.Create<MyData, Guid>(async cache =>
{
// inital load - is this okay?
cache.AddOrUpdate(await LoadLocalData());
// is this a valid way of doing this?
var sync = _serverSubject.Select(_ => GetDataFromServer())
.Subscribe(async task =>
{
var data = await task.ConfigureAwait(false);
cache.AddOrUpdate(data);
});
return new CompositeDisposable(sync);
}, d=> d.Id);
}
private IObservable<MyData> LoadLocalData()
{
return Observable.Timer(TimeSpan.FromSeconds(3)).Select(_ => new MyData("localdata"));
}
private async Task<MyData> GetDataFromServer()
{
await Task.Delay(2000).ConfigureAwait(true);
return new MyData("serverdata");
}
public void Dispose()
{
_cleanup?.Dispose();
}
}
public class MyData
{
public MyData(string value)
{
Value = value;
}
public Guid Id { get; } = Guid.NewGuid();
public string Value { get; set; }
}
And a simple Console app to run:
public static class TestProgram
{
public static void Main()
{
var service = new MyService();
service.AllData.Connect()
.Bind(out var myData)
.Subscribe(_=> Console.WriteLine("data in"), ()=> Console.WriteLine("COMPLETE"));
while (Continue())
{
Console.WriteLine("");
Console.WriteLine("");
Console.WriteLine($"Triggering Server Call, current data is: {string.Join(", ", myData.Select(x=> x.Value))}");
service.TriggerServer();
}
}
private static bool Continue()
{
Console.WriteLine("Press any key to call server, x to exit");
var key = Console.ReadKey();
return key.Key != ConsoleKey.X;
}
}
Looks very good for first try with Rx
I would suggest few changes:
1) Remove the Initialize() call from the constructor and make it a public method - helps a lot with unit tests and now you can await it if you need to
public static void Main()
{
var service = new MyService();
service.Initialize();
2) Add Throttle to you trigger - this fixes parallel calls to the server returning the same results
3) Don't do anything that can throw in Subscribe, use Do instead:
var sync = _serverSubject
.Throttle(Timespan.FromSeconds(0.5), RxApp.TaskPoolScheduler) // you can pass a scheduler via arguments, or use TestScheduler in unit tests to make time pass faster
.Do(async _ =>
{
var data = await GetDataFromServer().ConfigureAwait(false); // I just think this is more readable, your way was also correct
cache.AddOrUpdate(data);
})
// .Retry(); // or anything alese to handle failures
.Subscribe();
I'm putting what I've come to as my solution just in case there's others that find this while they're wandering the internets.
I ended up removing the Subjects all together and chaining together several SourceCache, so when one changed it pushed into the other and so on. I've removed some code for brevity:
public class MyService : IDisposable
{
private SourceCache<MyData, Guid> _localCache = new SourceCache<MyData, Guid>(x=> x.Id);
private SourceCache<MyData, Guid> _serverCache = new SourceCache<MyData, Guid>(x=> x.Id);
public MyService()
{
var localdata = _localCache.Connect();
var serverdata = _serverCache.Connect();
var alldata = localdata.Merge(serverdata);
AllData = alldata.AsObservableCache();
}
public IObservableCache<MyData, Guid> AllData { get; }
public IObservable<Unit> TriggerLocal()
{
return LoadLocalAsync().ToObservable();
}
public IObservable<Unit> TriggerServer()
{
return LoadServerAsync().ToObservable();
}
}
EDIT: I've changed this again to remove any chaining of caches - I just manage the one cache internally. Lesson is not to post too early.
I have a type mismatch error when reading the contents of table 'ImageHighlight'.
In designer.cs the table is:
public System.Data.Linq.Table<ImageHighlight>ImageHighlights
{
get
{
return this.GetTable<ImageHighlight>();
}
}
In my code I am trying to cache a small table in method LoadStaticCache() at ApplicationStart so I can access its contents later via GetHighlightImages().
public class StaticCache
{
private static ImageHighlight _images = null;
public static void LoadStaticCache()
{
// Get images - cache using a static member variable
using (var datacontext = new MHRDataContext())
{
_images = datacontext.ImageHighlights;
}
}
public static ImageHighlight GetHighlightImages()
{
return _images;
}
}
At code line _images = datacontext.ImageHighlights; I get error
Cannot implicitly convert type
System.Data.Linq.Table<HolidayRentals.Core.Domain.LinqToSql.ImageHighlight>
to HolidayRentals.Core.Domain.LinqToSql.ImageHighlight
They are both the same type.
datacontext.ImageHighlights is a Table which is an IQueryable of ImageHighlight. _imagess type is ImageHighlight. You can not convert these types to each other.
Since you want some caching mechanism and _images indicates that it should contain multiple instance of images then you should change the type of _images.
Change your code to this:
public class StaticCache
{
private static List<ImageHighlight> _images = null;
public static void LoadStaticCache()
{
// Get images - cache using a static member variable
using (var datacontext = new MHRDataContext())
{
_images = datacontext.ImageHighlights.ToList();
}
}
public static List<ImageHighlight> GetHighlightImages()
{
return _images;
}
}
When trying to compile my c# windows app I am getting the following error:
The name 'GetActiveLB' does not exist in the current context
Here's the code that calls that function:
using F5LTMMaintenance;
......
private void btnLBSetA_Click(object sender, EventArgs e)
{
List<string> range = GetActiveLB();
foreach (string item in range)
{
// Do something with item
}
}
Then I have a class with the following:
namespace F5LTMMaintenance
{
public class F5LTM<T>
{
public List<T> GetActiveLB()
{
var client = new RestClient("mylb.domain.local");
var request = new RestRequest("mgmt/tm/cm/failover-status", Method.GET);
var queryResult = client.Execute<List<T>>(request).Data;
return queryResult == null ? new List<T>() : queryResult;
}
}
}
The GetActiveLB function does exist, its a public function so why am I getting this error? Any help would be appreciated.
It has to be used with an instance of F5LTM<T>.
e.g.:
var f5ltm = new F5LTM<string>();
List<string> range = f5ltm.GetActiveLB();
Alternatively, if you declare it as static like this:
public class F5LTM //not generic here
{
public static List<T> GetActiveLB<T>() //generic here and static
{
//unchanged
}
}
Usage:
List<string> range = F5LTM.GetActiveLB<string>();
Or with C# 6 using static syntax:
using static F5LTMMaintenance.F5LTM; //at top of file
List<string> range = GetActiveLB<string>();
This is as close as you can get to the code you posted.
Yes it's a public function but it's defined inside a different class than your calling event handler class. You need to create a instance of your class F5LTM<T> and on that instance call your method GetActiveLB() rather like
private void btnLBSetA_Click(object sender, EventArgs e)
{
F5LTM<Type> test = new F5LTM<Type>();
List<string> range = test.GetActiveLB();
You will need an instance of your F5LTM class (say typF5LTM), to be able to call typF5LTM.GetActiveLB(). Or you need to make GetActiveLB a static function to be able to call it without an instance like F5LTM.GetActiveLB();
As another poster pointed out, you have to call the method on the class.
F5LTM<string> listItems = new F5LTM<string>();
List<string> range = listItems.GetActiveLB();
I have a few static Dictionary object that holds some constants list for me so I wouldn't have to load them from database each time my website loads (for example: a list of countries, a list of categories).
So I have a static function that checks if the instance is null, and if it is query the database, instantiate the static variable, and populate it with data.
Since it is a website, there could be a case that more than one person tries to access that information at the same time while the object is null, and all those who do will call that process at the same time (which is really not necessary, causes unneeded queries against the DB, and could cause duplicated objects in the list).
I know there's a way to make this kind of loading thread-safe (just not really sure how) - could someone point me in the right direction? should I use a lock?
Thanks
UPDATE II:
This is what I wrote (is this a good thread-safe code?)
private static Lazy<List<ICountry>> _countries = new Lazy<List<ICountry>>(loadCountries);
private static List<ICountry> loadCountries()
{
List<ICountry> result = new List<ICountry>();
DataTable dtCountries = SqlHelper.ExecuteDataTable("stp_Data_Countries_Get");
foreach (DataRow dr in dtCountries.Rows)
{
result.Add(new Country
{
ID = Convert.ToInt32(dr["CountryId"]),
Name = dr["Name"].ToString()
});
}
return result;
}
public static List<ICountry> GetAllCountries()
{
return _countries.Value;
}
You can use Lazy to load a resource in a lazy and thread-safe manner:
Lazy<List<string>> countries =
new Lazy<List<string>>(()=> /* get your countries from db */);
Update:
public static class HelperTables
{
private static Lazy<List<ICountry>> _countries;
static HelperTables //Static constructor
{
//Instantiating the lazy object in the static constructor will prevent race conditions
_countries = new Lazy<List<ICountry>>(() =>
{
List<ICountry> result = new List<ICountry>();
DataTable dtCountries = SqlHelper.ExecuteDataTable("stp_Data_Countries_Get");
foreach (DataRow dr in dtCountries.Rows)
{
result.Add(new Country
{
ID = Convert.ToInt32(dr["CountryId"]),
Name = dr["Name"].ToString()
});
}
return result;
});
}
public static List<ICountry> GetAllCountries()
{
return _countries.Value;
}
}
If you're using .NET 4.0, you can use the builtin Lazy generic class.
private static Lazy<YourObject> data = new Lazy<YourObject>(YourInitializationFunction);
public static YourObject Data { get { return data.Value; } }
Note that you have to add a static constructor to the class where you define this, otherwise it's not completely thread-safe.
If you're not on .NET 4.0+, you can just write your own code. The basic pattern looks something like this:
private static YourObject data;
private static object syncObject = new object();
public static YourObject Data
{
get
{
if (data == null)
{
lock (syncObject)
{
if (data != null)
return data;
var obj = new YourObject();
return (YourObject)Interlocked.Exchange(ref data, obj);
}
}
return data;
}
}
I have this sample data. Right now it is defined in a seperate C# file like this:
public class SampleData{
public static ObservableCollection<Product> GetSampleData(){
ObservableCollection<Product> teams = new ObservableCollection<Product>();
}
}
and I load the obsevableCollection inside GetSampleData().
It works and I am able to get the Sample-Data anywhere in my program.
But how can I redesign this code so that I can create the sample data on the fly from outside the class?
What you are trying to implement is called a singleton pattern. It allows you to store a single instance of an object.
Basically your problem is that every time you call GetSampleData you are creating a new instance of the ObservableCollection<Product> so you can’t get the same data gain by calling the method again. Your actual sample I think is not what you meant because in it’s posted form it wouldn’t compile because you missed the return teams;.
I am guessing you want something like this:
public class SampleData
{
private static ObservableCollection<Product> _Instance;
public static ObservableCollection<Product> Instance
{
get
{
// Create a new collection if required.
if (SampleData._Instance == null)
{
// Cache instance in static field.
SampleData._Instance = new ObservableCollection<Product>();
}
// Return new or existing collection.
return SampleData._Instance;
}
}
}
Basically we are creating the object instance on the first call so when you call the Instance property again you get the same instance.
Use it like this:
// Add the data to the ObservableCollection<Product>.
SampleData.Instance.Add(new dataObjectOrWhatEver());
// Get index 0 from the collection.
var someObject = SampleData.Instance[0];
public class SampleData{
static ObservableCollection<Product> teams = null;
static public ObservableCollection<Product> Teams{
get{
if(teams == null)
teams = GetSampleData();
return teams;
}
set{
teams = value;
}
}
// make this one private
private static ObservableCollection<Product> GetSampleData(){
ObservableCollection<Product> t = new ObservableCollection<Product>();
// fill t with your data
return t;
}
}
AND for the cunsumer:
public class MyCunsumerClass{
// the method that uses the Team that provided by SampleData
public void MyMethod(){
this.flatteningTreeView.ItemsSource = SampleData.Teams;
}
public void MyFillerMethod(){
var my_new_data = new ObservableCollection<Product>(); // or anything else you want to fill the Team with it.
SampleData.Teams = my_new_data;
// SampleData.Teams has new value you suplied!
}
public void MyChangerMethod(){
var t = SampleData.Team;
t.AnyProperty = my_value;
t.OtherProperty = my_value_2;
// SampleData.Team's properties changed!
}
}