I have a static class which is used to access a static concurrentdictionary:
public static class LinkProvider
{
private static ConcurrentDictionary<String, APNLink.Link> deviceLinks;
static LinkProvider()
{
int numProcs = Environment.ProcessorCount;
int concurrencyLevel = numProcs * 2;
deviceLinks = new ConcurrentDictionary<string, APNLink.Link>(concurrencyLevel, 64);
}
public APNLink.Link getDeviceLink(string deviceId, string userId)
{
var result = deviceLinks.First(x => x.Key == deviceId).Value;
if (result == null)
{
var link = new APNLink.Link(username, accountCode, new APNLink.DeviceType());
deviceLinks.TryAdd(deviceId, link);
return link;
}
else
{
return result;
}
}
public bool RemoveLink(string deviceId)
{
//not implmented
return false;
}
}
how can I make use of this class in my controller in an asp.net
Ie I want to go:
LinkProvider provider;
APNLink.Link tmpLink = provider.getDeviceLink(id, User.Identity.Name);
//use my link
Back ground. The dictionary is used to save a link object between states / requests in a asp.net web api program. So when the service needs to use the link, it asks the linkprovider to find a link for it and if there isn't one it must create one. So I need the dictionary object to the same instance in all my http requests.
So I need the dictionary object to the same instance in all my http
requests
Then use a static class, and make every method static too, so you could call it using the following syntax:
APNLink.Link tmpLink = LinkProvider.getDeviceLink(id, User.Identity.Name);
That being said, you should be aware that in-memory static variables in an ASP.Net application are not always safe to use, because your application isn't stateless and in case the application pool is recycled, your dictionary will be re-instantiated.
Related
I have a following method in my command handler that gets variables from another method,im trying to pass those variable into the CreateUser(NewAccount); method but it always comes back as null
public async Task ExecuteAsync(CreateUserAccountCommand command)
{
var result = await _client.CreateUser(GetAccountFrom(command)); // so this line gets the variables from GetAccountFrom(command)
_httpContextAccessor.HttpContext.Items["CreateUserAccountCommand"] = result;
}
private Account GetAccountFrom(CreateUserAccountCommand command)
{
var NewAccount = new Account();
NewAccount.FirstName = command.FirstName;
NewAccount.LastName = command.LastName;
return NewAccount()
}
however when i call CreateUser to pass in the variables into NewAccount thats coming from GetAccountFrom(command) it passes it in as a null
public System.Threading.Tasks.Task<Account> CreateUser(Account NewAccount,)
{
return base.Channel.CreateUser(NewAccount);
}
What am i doing wrong?
You are creating a new instance of NewAccount in your return statement.
private Account GetAccountFrom(CreateUserAccountCommand command)
{
var newAccount = new Account();
newAccount.FirstName = command.FirstName;
newAccount.LastName = command.LastName;
return newAccount; // <- Return the variable
}
You are creating object with new keyword. All you need to do is to return this object from your method with simple call:
return NewAccount;
The way you do it now is that you are returning result of NewAccount() method (whatever it is, apparently null), which is not what you want.
Also you might want to inspect why NewAccount() returns always null.
Your code has many anti patterns but it seems like you have a method somewhere in the base newAccount(); This is why inheritance should be avoided (for beginners and mids)
also the convention for private local variables lowercase.. as to NOT CONFUSE yourself.
private Account GetAccountFrom(CreateUserAccountCommand command)
{
var newAccount = new Account();
newAccount.FirstName = command.FirstName;
newAccount.LastName = command.LastName;
return newAccount;
}
or to completely avoid confusion just do this
private Account GetAccountFrom(CreateUserAccountCommand command)
{
return new Account{
FirstName = command.FirstName,
LastName = command.LastName,
}
}
But to avoid anti-patterns and spaghetti code you should really make an extension method which is much more S.O.L.I.D !
namespace you.company
{
public static CommandExtensions{
public static Account GetAccountFrom(this CreateUserAccountCommand command)
{
return new Account
{
FirstName = command.FirstName,
LastName = command.LastName,
};
}
}
I was wondering for some time what is the proper way to make a new instance of an dbcontext? I got some problem with it because when I make up change in my database through SQL Server my context doesn't update the data. Let me explain how my website work.
We are doing an appointment website for our customer to take appointment obviously. we will hosting all database on our server. How it work is the application made up 2 connection:
first connection
this connection connect all the time to the same database let's call it master.
It'll redirect the user to the good database with the url code in it example:
www.example.com/foo
the server will check for the code where here is foo
So it'll lookup in the table to matchup the code and then take the good database name where it should redirect and it's here that my second connection come's up
Second connection
This one will make the connection to the correct database according to the data the master has return. From here all seems to work well except for the DBContext that actually never update because I don't instantiate it correctly and I don't have an large experience with it. Here's the code i did with my coworker:
using System;
using System.Data.EntityClient;
using System.Data.SqlClient;
using System.Linq;
using System.Threading;
using System.Web;
using System.Web.Routing;
using WebRV.Models.Entities;
namespace WebRV.RouteDb
{
public class DbConnection
{
private static DbConnection instance;
private Cliniciel_WebRV_Entities db;
private String connectionString;
private readonly Cliniciel_WebRV_MasterEntities masterDb = new Cliniciel_WebRV_MasterEntities();
private Int32 idCie;
private static readonly object myLock = new object();
private DbConnection() {
var context = new HttpContextWrapper(System.Web.HttpContext.Current);
var routeData = RouteTable.Routes.GetRouteData(context);
// Use RouteData directly:
String code = routeData.Values["code"].ToString();
//String code = Thread.CurrentContext. .RequestContext.RouteData.Values["code"].ToString();
var response = masterDb.SYS_tbCustDBLocation.Where(p => p.CustDBLocationCode == code).ToList();
if (response.Count == 1)
{
try
{
db = CreateConnection(response.FirstOrDefault());
idCie = (db.SYS_vwCie.Where(p => p.ClinicielWebName == code).FirstOrDefault()).IdCie;
}
catch (Exception e)
{
throw e;
}
}
else {
throw new FormatException();
}
}
private Cliniciel_WebRV_Entities CreateConnection(SYS_tbCustDBLocation data)
{
connectionString = *****
db = new Cliniciel_WebRV_Entities();
db.Database.Connection.ConnectionString = connectionString;
db.Database.Connection.Open();
return db;
}
private static void CreateInstance() {
instance = new DbConnection();
}
public static DbConnection GetInstance() {
lock (myLock)
{
if (instance == null)
{
CreateInstance();
}
}
return instance;
}
public String GetConnectionString()
{
return connectionString;
}
public Cliniciel_WebRV_Entities GetConnection()
{
return db;
}
public Int32 GetIdCie()
{
//hard code 1 but test
//return idCie;
return 1;
}
}
}
and here's an example of how I use it:
//[CompanyCodeFilter]
public class HomeController : AppointementController
{
//public static Cliniciel_WebRV_Entities entityDB = DbConnection.GetConnection();
public HomeController()
{
base.Refresh();
}
public JsonResult GetConsultationDescription(Int32 idService)
{
//base.Refresh();
entityDB.Set<SYS_vwService>().AsNoTracking();
var motifDescription = entityDB.SYS_vwService.Where(s => s.IDLang == cultureName && s.IdService == idService && s.IdCie == idCie).FirstOrDefault();
var base64 = Convert.ToBase64String(motifDescription.ServiceImage);
var imgSrc = String.Format("data:image/gif;base64,{0}", base64);
var imageDecode = imgSrc;
if (base64 == "AA==")
{
imageDecode = "";
}
var result = new { motifDescription, imageDecode };
return Json(result, JsonRequestBehavior.AllowGet);
}
}
Here base.refresh() call this:
using System;
using System.Linq;
using WebRV.Filters;
using WebRV.Localization;
using WebRV.Models.Entities;
using WebRV.RouteDb;
namespace WebRV.Controllers
{
//[CompanyCodeFilter]
public class AppointementController : BaseController
{
protected Cliniciel_WebRV_Entities entityDB;
protected Int32 idCie;
protected String cultureName;
//public AppointementController() {
// Refresh();
//}
//Permet de bien vérifier quel DB utilisé, quel idCie et quel cultureName.
protected void Refresh() {
entityDB = DbConnection.GetInstance().GetConnection();
idCie= DbConnection.GetInstance().GetIdCie();
cultureName = CultureLocalization.GetCulture();
//cultureName = "en-ca";
}
}
}
If someone can help me to instantiate the connection properly it'll be appreciate thank you
I think you need to better understand how the db context works.
It's a combination of many design patterns but at a basic level, it's essentially a unit of work that tracks changes to the objects that represent data. Because of this, it's not meant to be used as a connection that stays open all the time and you can just go back and forward, although you could use it like that to a certain extent.
From your code, it looks like you are using it in an ASP.NET MVC application. Because of the nature of the application, you can do one of two things:
You can create the db context whenever you need to use it, or
You can create the db context as a property of the controller
In the end, they somewhat amount to the same thing. I personally would recommend you create an instance of the context whenever you need to use it, making sure to dispose of it properly. You could then have a base controller class that exposes a CreateConnetion() method that creates an instance for your contexts, sort of like the Cliniciel_WebRV_Entities CreateConnection() method you already have, except that you don't need to open the connection explicitly and the connection string can be passed on as a constructor parameter if you add a partial class and implement one for the context. Something like this:
public partial class Cliniciel_WebRV_Entities
{
public Cliniciel_WebRV_Entities(string nameOrConnectionString):base(nameOrConnectionString)
{
}
}
You can then use it like this:
private Cliniciel_WebRV_Entities CreateConnection()
{
//Code to figure out which db to connect to (based on the other connection. You should consider caching that too if it doesn't change very often)
var nameOrConnectionString = FigureOutConnection();
var db = new Cliniciel_WebRV_Entities(nameOrConnectionString);
return db;
}
Keep in mind that the context depends on the metadata so make sure your connection string reflects that.
In your code, you would then consume it like this:
public JsonResult GetConsultationDescription(Int32 idService)
{
using(var entityDB = CreateConnection())
{
var motifDescription = entityDB.SYS_vwService.Where(s => s.IDLang == cultureName && s.IdService == idService && s.IdCie == idCie).FirstOrDefault();
var base64 = Convert.ToBase64String(motifDescription.ServiceImage);
var imgSrc = String.Format("data:image/gif;base64,{0}", base64);
var imageDecode = imgSrc;
if (base64 == "AA==")
{
imageDecode = "";
}
var result = new { motifDescription, imageDecode };
return Json(result, JsonRequestBehavior.AllowGet);
}
}
}
Another thing to remember and something that bites every newcomer is that you should not pass entities (objects from the context) to the views in models. This is because once the context is disposed, objects with navigational properties will break. There are ways around it but not recommended. Map the objects to models instead.
By the way, don't forget to call the SaveChanges() method after modifying entities or the database will not be updated with the changes.
You should really read very carefuly from some very good sources about DbContext: for example:
http://www.entityframeworktutorial.net/EntityFramework4.3/dbcontext-vs-objectcontext.aspx
https://msdn.microsoft.com/en-us/library/system.data.entity.dbcontext(v=vs.113).aspx
When you pass a DbContext to service or business class, you pass it as a Value not as a reference so you will loss all changes made in client code, the option is to pass it as a reference but it is not a safe and not a good practice but, if you instead pass the context as a delegate you are passing a reference to the object directly so its the best approch in order to keep your injected context with changes from business/service layers.
Here is the idea:
Option 1, pass it as reference, not recommended:
public void Call()
{
//Attach changes to context, Passing as reference
Process(ref _context);
//All changes attached to context
_context.SaveChanges();
}
public void Process(ref Cliniciel_WebRV_MasterEntities context)
{
var c = context();
//Get entites dbcontext
//Update entites
}
Option 2, pass it as a delegate, best approch:
public void Call()
{
//Attach changes to context, Passing as reference
Process(() => _context);
//All changes attached to context
_context.SaveChanges();
}
public void Process(Func<Cliniciel_WebRV_MasterEntities> context)
{
var c = context();
//Get entites dbcontext
//Update entites
}
I have a helper function which deserializes an XML file, and generates c# objects from it.
After that, the objects are added into server memory. The only way of adding something in the server's memory is only through this function.
public class DeserializeXmlHelper
{
public void DeserializeXml(Guid xml_Id, decimal version)
{
// heavy process here which takes about 3 seconds
}
}
This function is being called by different clients using an API method (made in Asp.net MVC API).
When calling the API, can i prevent the execution of the function if somebody else already called the same function with the same parameters?
Something like this, but i don't know if it is a good way of doing it.
public class DeserializeXmlHelper
{
private static readonly ConcurrentDictionary<string, object> _processes = new ConcurrentDictionary<string, object>();
public void DeserializeXml(Guid xml_Id, decimal version)
{
string processKey = string.Format("{0}_v{1}", xml_Id, version.ToString("#0.0"));
object processLocker = null;
if (_processes.TryGetValue(processKey, out processLocker) == false)
{
processLocker = new object();
_processes.TryAdd(processKey, processLocker);
}
lock (processLocker)
{
// heavy process here which takes about 3 seconds
_processes.TryRemove(processKey);
}
}
}
EDITED - New version
Tim Roger's answer is working successfully.
However, if i want to return only when the initial call has finished, can i do something like this? (I am using ConcurrentDictionary because i don't know how to add locks, but the idea should be the same)
public class DeserializeXmlHelper
{
private static readonly ConcurrentDictionary<string, string> _processes = new ConcurrentDictionary<string, string>();
public void DeserializeXml(Guid xml_Id, decimal version)
{
string _processKey = string.Format("{0}_v{1}", xml_Id, version.ToString("#0.0"));
string _processValue = null;
if (_processes.TryGetValue(_processKey, out _processValue) == true)
{
// function already called with the same parameters
do
{
System.Threading.Thread.Sleep(100);
}
while(_processes.TryGetValue(_processKey, out _processValue) == true)
return;
}
try
{
_processes.TryAdd(_processKey, _processValue);
var begin = "begin process";
System.Threading.Thread.Sleep(10000);
var end = "ending process";
}
finally
{
_processes.TryRemove(_processKey, out _processValue);
}
}
}
Your original solution was not far off but you seemed to always be running the process regardless of the current state.
Even though you have used a concurrent dictionary, you also need a lock to lock the entire dictionary while you are updating its state, since the thread could be interrupted between TryGetValue and Add.
private static readonly ConcurrentDictionary<string, object> _processes = new ConcurrentDictionary<string, object>();
private static readonly object _dictionaryLock = new object();
public void DeserializeXml(Guid xml_Id, decimal version)
{
string processKey = string.Format("{0}_v{1}", xml_Id, version.ToString("#0.0"));
object processLocker = null;
bool needsExecuting = false;
lock (_dictionaryLock)
{
if (_processes.TryGetValue(processKey, out processLocker) == false)
{
needsExecuting = true;
processLocker = new object();
_processes.Add(processKey, processLocker);
}
}
lock (processLocker)
{
if (needsExecuting)
{
// heavy process here which takes about 3 seconds
_processes.Remove(processKey);
}
}
}
I have a class that implements singleton pattern as you can see below:
public class SearchSingletonObject
{
private static SearchSingletonObject foundation = null;
public SearchObject Object= null;
private static StringCollection views = null;
private static object control = new object();
public IEnumerable<string> blacklist = null;
public static void ClearFoundation()
{
foundation = null;
}
public static SearchSingletonObject Foundation
{
get
{
if (foundation == null)
{
lock (control)
{
if (foundation == null)
{
foundation = new SearchSingletonObject();
var blacks = File.ReadAllText(HostingEnvironment.ApplicationPhysicalPath + "\\blacklist.txt");
foundation.blacklist = blacks.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries).Where(x => !string.IsNullOrEmpty(x) || x != " ");
views = new StringCollection();
var items = ConfigurationManager.AppSettings["SearchView"].Split(',');
foreach (var item in items)
{
views.Add(item);
}
foundation.Object = new SearchObject(ConfigurationManager.AppSettings["ContentDistributor"],
ConfigurationManager.AppSettings["Port"],
views);
}
}
}
return foundation;
}
}
public SearchSingletonObject()
{
}
}
We're using this class in our wcf rest services. But in non-periodic intervals we get "Value can not be null" errors. Here is my log file:
08.03.2011 11:40:39 ERROR Message : Value cannot be null.
Parameter name: source
StackTrace : at System.Linq.Enumerable.Where[TSource](IEnumerable`1 source, Func`2 predicate)
at Search.Service.SearchService.Search(String keyword, Int32 offset, Int32 hit, String navstate, String username, Boolean issecure, Int32 suggest, String sortref, String fields, Int32 IsFirstSearch, String misspelled, String category) in D:\tfs\Hey\HeyRestApi\HeyService\HeyService.cs:line 68
Log file mentions the row below in my service:
var blacks = SearchSingletonObject.Foundation.blacklist.Where<string>(x => item.Equals(x)).FirstOrDefault();
It seems strangely the "blacklist" object getting null value. After the error, we have to reset IIS, to get application working. We can not reproduce the error on our local servers. It just happens in our customers production environment.
How can we solve that problem and what can be the reason of this strange error?
Thanks in advance,
Double-checked locking is broken.
Short explanation:
Even if foundation is non-null, without a lock you can't be sure that foundation's members are non-null from the point of view of your processor.
You need to remove the if statement that's outside the lock.
Update
A better solution is to mark foundation as volatile:
private static volatile SearchSingletonObject foundation = null;
The need for volatile modifier in double checked locking in .NET has more details.
I have a very subtle bug that I'm having trouble identifying.
Background:
We have 2 sites running off the same application on the same web server.
SiteA -- accessed by www.SiteA.com
SiteB -- accessed by www.SiteB.com
When the request first comes in, the siteId is identified based on the Host and stored in the Session as follows:
protected void Application_BeginRequest(object sender, EventArgs e)
{
string host = Request.Url.Host;
int siteId = new SiteManager().GetSiteByUrl(host).SiteId;
if (SessionUser.Instance().SiteId != siteId)
{
SessionUser.Instance().SiteId = siteId;
}
}
This ID used later in determining what data to retreive and to determine what style to present:
// this happens during an initialization phase
_siteConfiguration = _siteManager.GetSiteById(SessionUser.Instance().SiteId);
// then later:
private void SetPageTheme()
{
string theme = null;
switch (_siteConfiguration.SiteId)
{
case ConfigurationHelper.SITE.A:
theme = "SiteATheme";
break;
case ConfigurationHelper.SITE.B:
theme = "SiteBTheme";
break;
}
Page.Theme = theme;
}
The problem:
the problem I'm facing is if you load both sites at almost exactly the same time, i.e. within milliseconds, sometimes SiteA will load with SiteB's theme and vice versa. This doesn't happen very often but it has come to the attention of the client so it's now a problem.. Something is happening somewhere within those few milliseconds in the difference between SiteA loading and SiteB loading, and I don't know how to identify what that is.
The question:
Does anyone have any ideas what could be going wrong here? Something is getting confused somewhere. Is it IIS mixing up the requests? Is it the Session mixing up the site it's supposed to return the SiteId for?
If any more info is needed, I'll supply it.
Update:
For reference, this is the definition of SessionUser (basically, create a static instance of an object to get the SiteId value from the Session):
public class SessionUser
{
private static SessionUser _instance;
public int SiteId { get; set; }
/// <summary>
///
/// </summary>
/// <returns></returns>
public static SessionUser Instance()
{
if (null == _instance)
{
_instance = new SessionUser();
if (null != HttpContext.Current.Session)
{
if (null == HttpContext.Current.Session["User"])
{
if (HttpContext.Current.Request.QueryString["sid"] != null)
{
int nSiteId = int.Parse(HttpContext.Current.Request.QueryString["sid"]);
_instance.SiteId = nSiteId;
HttpContext.Current.Session["User"] = _instance;
}
}
else
{
_instance = (SessionUser) HttpContext.Current.Session["User"];
}
}
}
return _instance;
}
}
Without knowing what the 'SessionUser' class looks like, I can only speculate.
I will assume that SessionUser.Instance() returns a 'static' instance (or member rather).
Now, these will be shared across the entire application. So it makes sense that this cannot be shared between 2 sites.
I suggest you rather use HttpContext to store the setting at BeginRequest.
The code will then look like the following:
class SessionUser
{
public static SessionUser Instance()
{
var ctx = HttpContext.Current;
var su = ctx["SessionUser"] as SessionUser;
if (su == null)
{
ctx["SessionUser"] = su = new SessionUser();
}
return su;
}
}
I guess you could put the code that stores the current Site ID inside a lock block, but this may hamper performance. It makes more sense to use something not shared by both sites, as leppie says.
For the lock example:
if (SessionUser.Instance().SiteId != siteId)
{
lock(somePrivateStaticObject)
{
if (SessionUser.Instance().SiteId != siteId)
{
SessionUser.Instance().SiteId = siteId;
}
}
}