I know I shouldn't have to ask this but whatever it is I am missing is driving me nuts! I have done this many times before and I can only put it down to old age and slight senility.
I have a class with two objects that get initialized in the constructor...
public class EbayFunctions
{
private static ApiContext apiContext = null;
private static List<StoreCategoriesFlattened> storeCategories = new List<StoreCategoriesFlattened>();
public EbayFunctions()
{
ApiContext apiContext = GetApiContext();
List<StoreCategoriesFlattened> storeCategories = GetFlattenedStoreCategories();
}
public string GetStoreCategoryIdForItem(string category)
{
var result = storeCategories.Find(x => x.CCDatabaseMatch == category);
return ""; //Ignore will return a value
}
}
then I have a forms app (test harness) that makes use of the class and on button click I call a method...
namespace EbayTestHarness
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void cmdGetEbayStoreCatID_Click(object sender, EventArgs e)
{
EbayFunctions ebf = new EbayFunctions();
string ddd = ebf.GetStoreCategoryIdForItem("Motors > Bikes");
}
}
}
However apiContext persists between calls but storeCategories gets populated on EbayFunctions ebf = new EbayFunctions(); and is null when string ddd = ebf.GetStoreCategoryIdForItem("Motors > Bikes"); is called.
I know its something stupid but what am I missing?
Your problem is here:
private static ApiContext apiContext = null;
private static List<StoreCategoriesFlattened> storeCategories = new List<StoreCategoriesFlattened>();
public EbayFunctions()
{
ApiContext apiContext = GetApiContext(); // local!!
List<StoreCategoriesFlattened> storeCategories = GetFlattenedStoreCategories(); // local!!
}
You're not setting the static fields - you're introducing local variables that then go out of scope and are (eventually) garbage collected. Take out the type indicators to set the static fields:
public EbayFunctions()
{
apiContext = GetApiContext();
storeCategories = GetFlattenedStoreCategories();
}
Also, as #PatrickHofman points out, the initialization of static members should be done once - preferably in a static constructor:
static EbayFunctions()
{
apiContext = GetApiContext();
storeCategories = GetFlattenedStoreCategories();
}
Related
Task is to call a third party service/wrapper multiple times and get the response. Below is the sample code and I am trying to figured out how to create singleton instance for the service.
class Program
{
static void Main(string[] args)
{
List<string> trips = new List<string>();
trips.Add("ABC");
trips.Add("XYZ");
foreach (string s in trips) {
Test.TestMethod(s);
}
}
}
public static class Test
{
public static bool TestMethod(string trip)
{
BridgeApiClient bridgeApiClient = new BridgeApiClient("http://localhost/Service.svc", "username", "password");
TripRequest tr = new TripRequest();
tr.TripNumber = trip;
var response = bridgeApiClient.GetTrip(tr);
return true;
}
}
You can just declare a static member variable and use that:
public static class Test
{
private static readonly BridgeApiClient bridgeApiClient = new BridgeApiClient("http://localhost/Service.svc", "username", "password");
public static bool TestMethod(string trip)
{
TripRequest tr = new TripRequest();
tr.TripNumber = trip;
var response = bridgeApiClient.GetTrip(tr);
return true;
}
}
I have a static (large)data from database that i need to send to clients so i created a singleton class that get the data from the database and populate the list.
I start the service host inside the windows service, so when an outside call the wcf the data comes empty, what should i do?
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class CacheDataService : ICacheDataService
{
public List<Sale> GetDataFromImobDateById(int idImob, DateTime date)
{
return SalesHelper.Instance.GetDataFromImobDate(idImob, date);
}
}
public class SalesHelper
{
static Lazy<SalesHelper> singleton = new Lazy<SalesHelper>(() => new SalesHelper());
public static SalesHelper Instance { get { return singleton.Value; } }
ICacheData<Sale> _cache;
List<Sale> CacheData = new List<Sale>();
public void SetCache(ICacheData<Sale> cacheData)
{
_cache = cacheData;
}
public void ReloadCache()
{
CacheData.Clear();
GetAllData();
}
public void GetAllData()
{
CacheData = _cache.GetAllData();
}
public List<Sale> GetDataFromImobDate(int idImob, DateTime date)
{
var result = (from r in CacheData
where r.Data_Alteracao.Equals(date)
&& r.Id_Imobiliaria.Equals(idImob)
select r).ToList();
return result;
}
}
and in the Service i start the ServiceHost and the cache
_tempSales = new SalesHelper();
ICacheData<Sale> _cacheSale = new Sale();
_tempSales.SetCache(_cacheSale);
_tempSales.GetAllData();
_service = new ServiceHost(typeof(CacheDataService));
I think your are missing the initialization of SalesHelper.Instance.
doing this new Lazy<SalesHelper>(() => new SalesHelper()); leads to get an intance of _cache not initialized.
So we have a couple of workaround to chose.
One of them is initilize the Intance:
SalesHelper.Instance.SetCache(_cacheSale);
It should look like this:
//_tempSales = new SalesHelper();
ICacheData<Sale> _cacheSale = new Sale();
//_tempSales.SetCache(_cacheSale);
//_tempSales.GetAllData();
SalesHelper.Instance.SetCache(_cacheSale);
SalesHelper.Instance.GetAllData(); //Now it should return the info
_service = new ServiceHost(typeof(CacheDataService));
The other one is replace your prop Intance with a factory method GetInstance() which should receive the cache and set it if it is needed.
Let me know if the first workaround solve your problem.
Is there a possibility to cache a collection, retrieved using WCF from an OData service.
The situation is the following:
I generated a WCF service client with Visual Studio 2015 using the metadata of the odata service. VS generated a class inheriting from System.Data.Services.Client.DataServiceContext. This class has some properties of type System.Data.Services.Client.DataServiceQuery<T>. The data of some of these properties change seldom. Because of performance reasons I want the WCF client to load these properties just the first time and not every time I use it in the code.
Is there a built in possibility to cache the data of these properties? Or can I tell the service client not to load specific proeprties newly every time.
Assuming the service client class is ODataClient and one of its properties is `Area, for now I get the values in the following way:
var client = new ODataClient("url_to_the_service");
client.IgnoreMissingProperties = true;
var propertyInfo = client.GetType().GetProperty("Area");
var area = propertyInfo.GetValue(client) as IEnumerable<object>;
The reason why I do this in such a complicated way is, that the client should be very generic: The properties to be handled can be configured in a configuration file.
* EDIT *
I already tried to find properties in the System.Data.Services.Client.DataServiceContext class or the System.Data.Services.Client.DataServiceQuery<T> class for the caching. But i wasn't able to find any.
To my knowledge there is no "out of the box" caching concept on the client. There are options for caching the output of a request on the server which is something you might want consider as well. Googling "WCF Caching" would get you a bunch of info on this.
Regarding client side caching...#Evk is correct it is pretty straight forward. Here is an sample using MemoryCache.
using System;
using System.Runtime.Caching;
namespace Services.Util
{
public class CacheWrapper : ICacheWrapper
{
ObjectCache _cache = MemoryCache.Default;
public void ClearCache()
{
MemoryCache.Default.Dispose();
_cache = MemoryCache.Default;
}
public T GetFromCache<T>(string key, Func<T> missedCacheCall)
{
return GetFromCache<T>(key, missedCacheCall, TimeSpan.FromMinutes(5));
}
public T GetFromCache<T>(string key, Func<T> missedCacheCall, TimeSpan timeToLive)
{
var result = _cache.Get(key);
if (result == null)
{
result = missedCacheCall();
if (result != null)
{
_cache.Set(key, result, new CacheItemPolicy { AbsoluteExpiration = DateTimeOffset.Now.Add(timeToLive) });
}
}
return (T)result;
}
public void InvalidateCache(string key)
{
_cache.Remove(key);
}
}
}
This is an example of code that uses the cache...
private class DataAccessTestStub
{
public const string DateTimeTicksCacheKey = "GetDateTimeTicks";
ICacheWrapper _cache;
public DataAccessTestStub(ICacheWrapper cache)
{
_cache = cache;
}
public string GetDateTimeTicks()
{
return _cache.GetFromCache(DateTimeTicksCacheKey, () =>
{
var result = DateTime.Now.Ticks.ToString();
Thread.Sleep(100); // Create some delay
return result;
});
}
public string GetDateTimeTicks(TimeSpan timeToLive)
{
return _cache.GetFromCache(DateTimeTicksCacheKey, () =>
{
var result = DateTime.Now.Ticks.ToString();
Thread.Sleep(500); // Create some delay
return result;
}, timeToLive);
}
public void ClearDateTimeTicks()
{
_cache.InvalidateCache(DateTimeTicksCacheKey);
}
public void ClearCache()
{
_cache.ClearCache();
}
}
And some tests if you fancy...
[TestClass]
public class CacheWrapperTest
{
private DataAccessTestStub _dataAccessTestClass;
[TestInitialize]
public void Init()
{
_dataAccessTestClass = new DataAccessTestStub(new CacheWrapper());
}
[TestMethod]
public void GetFromCache_ShouldExecuteCacheMissCall()
{
var original = _dataAccessTestClass.GetDateTimeTicks();
Assert.IsNotNull(original);
}
[TestMethod]
public void GetFromCache_ShouldReturnCachedVersion()
{
var copy1 = _dataAccessTestClass.GetDateTimeTicks();
var copy2 = _dataAccessTestClass.GetDateTimeTicks();
Assert.AreEqual(copy1, copy2);
}
[TestMethod]
public void GetFromCache_ShouldRespectTimeToLive()
{
_dataAccessTestClass.ClearDateTimeTicks();
var copy1 = _dataAccessTestClass.GetDateTimeTicks(TimeSpan.FromSeconds(2));
var copy2 = _dataAccessTestClass.GetDateTimeTicks();
Assert.AreEqual(copy1, copy2);
Thread.Sleep(3000);
var copy3 = _dataAccessTestClass.GetDateTimeTicks();
Assert.AreNotEqual(copy1, copy3);
}
[TestMethod]
public void InvalidateCache_ShouldClearCachedVersion()
{
var original = _dataAccessTestClass.GetDateTimeTicks();
_dataAccessTestClass.ClearDateTimeTicks();
var updatedVersion = _dataAccessTestClass.GetDateTimeTicks();
Assert.AreNotEqual(original, updatedVersion);
}
}
My services take a DbContext in their constructor, and I have created a UnitOfWork class that contains all my services in order to make sure the same DbContext is used between them all.
Sample of unitofwork class
private myEntities myContext
public UnitOfWork()
{
myContext = new myEntities();
}
private RequestService requestService;
public RequestService RequestService
{
get
{
if (requestService == null)
requestService = new RequestService(myContext);
return requestService;
}
}
By Using this unitofwork class all the DbContext for my services are now consistent and a change made in one service will appear in another.
However if i need to change the actual Entity context class then that does not get persisted across each service.
Below i have a "Refresh" method that re-initializes it (I need to refresh the context so i can have this class work with some legacy code).
public void Refresh()
{
myContext = new myEntities();
}
However my service classes DbContext objects aren't passed by ref so the context is not set to a new instance of my entity class and this results in the context not being refreshed.
So I think i can solve this by passing by ref as shown below
Service class sample
MyEntities myContext;
public RequestService(ref MyEntities myContext)
{
this.myContext = myContext;
}
However i have seen people say you should not pass context classes by ref so i am curious if there is a better way out there and i am looking at this the wrong way?
Edit
Sorry turns out my proposed solution of passing by ref does not solve my problem, but i am still interested as to how i can update the entity context on the UnitOfWork class e.g. setting it to null and have that effect the service classes.
Never ever should you share DbContext, by reference or as reference. It is not thread safe.
http://msdn.microsoft.com/en-us/data/jj729737.aspx
If you need an easy way to generate multiple DbContext, use ObjectPool from Parallel Extensions Extras.
Update 1
#tia is correct in saying that the private instance will not be updated when original changes:
class Program
{
static void Main(string[] args)
{
var pool1 = new ObjectPool<IDbConnection>(() => new SqlConnection("Data Source=server1"));
var service = new Service(ref pool1);
pool1 = new ObjectPool<IDbConnection>(() => new SqlConnection("Data Source=server2"));
Console.WriteLine(service.Pool.GetObject().ConnectionString);
}
}
class Service
{
private ObjectPool<IDbConnection> connectionPool;
public Service(ref ObjectPool<IDbConnection> pool) { this.connectionPool = pool; }
public ObjectPool<IDbConnection> Pool { get { return connectionPool; } }
}
Will print "Data Source=server 1", even if it would be a static field.
Enter Monostate, a wicked pattern, very similar to Singleton.
class Program
{
static void Main(string[] args)
{
var mop = new MonoObjectPool();
mop.Pool = new ObjectPool<IDbConnection>(() => new SqlConnection("Data Source=server1"));
var service = new Service();
mop.Pool = new ObjectPool<IDbConnection>(() => new SqlConnection("Data Source=server2"));
Console.WriteLine(service.Pool.GetObject().ConnectionString);
}
}
internal class MonoObjectPool
{
private static ObjectPool<IDbConnection> pool1;
public ObjectPool<IDbConnection> Pool
{
get { return pool1; }
set { pool1 = value; }
}
}
class Service
{
public ObjectPool<IDbConnection> Pool { get { return new MonoObjectPool().Pool; } }
}
I am getting rid of the constructor for service, as I can always get the current IDbConnection generator. There will always be only one instance of it, regardless how many times someone instantiates the MonoObjectPool.
Update 2
The other option might be to use Autofac, but I am not too familiar with it, yet, so I can't give you an example how a type could get resolved in a service instance. Here is a simple example:
class Program
{
private static IContainer container { get; set; }
static void Main(string[] args)
{
var builder = new ContainerBuilder();
builder.RegisterType<DbCtx1>().As<IDbCtx>();
container = builder.Build();
using (var scope = container.BeginLifetimeScope())
{
var dbctx = scope.Resolve<IDbCtx>();
Console.WriteLine(dbctx.GetType());
}
builder = new ContainerBuilder();
builder.RegisterType<DbCtx2>().As<IDbCtx>();
container = builder.Build();
using (var scope = container.BeginLifetimeScope())
{
var dbctx = scope.Resolve<IDbCtx>();
Console.WriteLine(dbctx.GetType());
}
}
}
interface IDbCtx
{
}
class DbCtx1 : IDbCtx { }
class DbCtx2 : IDbCtx { }
Update 3
So going back to the Monostate, this works as expected:
class Program
{
static void Main(string[] args)
{
var mop = new MonoObjectPool();
mop.Pool = new ObjectPool<IDbConnection>(() => new SqlConnection("Data Source=server1"));
var service = new Service(mop);
mop.Pool = new ObjectPool<IDbConnection>(() => new SqlConnection("Data Source=server2"));
Console.WriteLine(service.Pool.GetObject().ConnectionString);
}
}
internal class MonoObjectPool
{
private static ObjectPool<IDbConnection> pool1;
public ObjectPool<IDbConnection> Pool
{
get { return pool1; }
set { pool1 = value; }
}
}
class Service
{
private MonoObjectPool myPool;
public Service(MonoObjectPool pool) { myPool = pool; }
public ObjectPool<IDbConnection> Pool { get { return myPool.Pool; } }
}
I hope this helps.
An unhandled exception of type 'System.StackOverflowException' occurred in mscorlib.dll
In page_load event i am calling
if (mySession.Current._isCustomer)
{
Response.Redirect("Products.aspx");
}
mySession class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace ShoppingCartWebApp
{
public class mySession
{
// private constructor
private mySession() {}
// 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 _date { get; set; }
public String _loginId { get; set; }
public string _firstName { get; set; }
public string _userName { get; set; }
public string _role { get; set; }
public Boolean _isCustomer = false;
public Boolean _isAuth = false;
public Boolean _isGuest = true;
public ShoppingCart _cart = new ShoppingCart();
public ShoppingCart instance
{
get
{
return _cart;
}
set
{
_cart = value;
}
}
public void abandonSession()
{
// _date =
_loginId = null;
_firstName = null;
_cart = null;
_userName = null;
_role = null;
_isCustomer = false;
_isAuth = false;
}
}
}
it gives a stackoverflow exception. why?
ShoppingCart Class:
public class ShoppingCart
{
#region ListCart
public List<CartItem> Items { get; private set; }
public static SqlConnection conn = new SqlConnection(connStr.connString);
#endregion
#region CartSession
public ShoppingCart cart;
public ShoppingCart()
{
if (mySession.Current._cart == null)
{
cart = new ShoppingCart();
cart.Items = new List<CartItem>();
if (mySession.Current._isCustomer)
cart.Items = ShoppingCart.loadCart(mySession.Current._loginId);
mySession.Current._cart = cart;
}
else
{
cart = mySession.Current._cart;
}
}
}
This line of code causes infinite loop and stack overflow :
if (mySession.Current._isCustomer)
cart.Items = ShoppingCart.loadCart(mySession.Current._loginId);
it is initialized by each instance of mysession class. and its using its parent class.
even using singleton mySession can not solve the problem.
when this code is executing :
session = new mySession();
it tries to initialize new ShoppingCard. shopping card asks for singleton instance of mysession. this line of code is not executed yet :
HttpContext.Current.Session["__MySession__"] = session;
so goes to create a new instance of my session and ...
this means stack overflow !
you can correct it like this :
public static mySession Current
{
get
{
mySession session =
(mySession)HttpContext.Current.Session["__MySession__"];
if (session == null)
{
session = new mySession();
HttpContext.Current.Session["__MySession__"] = session;
session._cart = new ShoppingCart(); //initialize your shoppoing car after adding variable to session !
}
return session;
}
}
public ShoppingCart _cart;// = new ShoppingCart(); remove initialization
look at my comments in code.
The problem comes because of the relationship between mySession and ShoppingCart.
mySession has a member variable defined like so:
public ShoppingCart _cart = new ShoppingCart();
When the constructor of mySession is called, an instance of ShoppingCart is instantiated. When the constructor of ShoppingCart executes, it calls the mySession.Current static property. Because the constructor of ShoppingCart was called from within this same property (remember, we are still creating an instance of mySession in the original static call), it continues to recurse in this way until a StackOverflowException is raised.
To fix this, I suggest you take a look at your ShoppingCart class. Firstly, why does it need an instance of itself as a member variable? Secondly, if ShoppingCart needs to know information about the contents of mySession, your encapsulation is not correct. I suggest you pass the information needed into the constructor of ShoppingCart to avoid making a call back to mySession.Current.
Given your updated question, I think if you properly followed .Net naming guidelines (as outlined in my comment on your question), you should be able to easily figure out where the problem is. I suspect your calling code is similar, and not following the guidelines is obscuring what is actually happening from what you think is happening.
As a first step I would recommend doing this cleanup; it will likely make it clear where you're causing the overflow.