HttpApplication.Context null in Global.asax - c#

Referencing this answer regarding regenerating new SessionID
I created this code in my Global.asax.cs:
protected void Application_Start(object sender, EventArgs e)
{
Bootstrapper.Initialized += new EventHandler<ExecutedEventArgs>(Bootstrapper_Initialized);
}
void Bootstrapper_Initialized(object sender, Telerik.Sitefinity.Data.ExecutedEventArgs e)
{
if (e.CommandName == "Bootstrapped")
{
EventHub.Subscribe<ILoginCompletedEvent>(LoginCompletedEventVerification);
}
}
private void LoginCompletedEventVerification(ILoginCompletedEvent evt)
{
if (evt.LoginResult == UserLoggingReason.Success)
{
var manager = new SessionIDManager();
var oldId = manager.GetSessionID(Context);
var newId = manager.CreateSessionID(Context);
bool isAdd = false, isRedir = false;
manager.SaveSessionID(Context, newId, out isRedir, out isAdd);
var ctx = HttpContext.Current.ApplicationInstance;
var mods = ctx.Modules;
var ssm = (SessionStateModule)mods.Get("Session");
var fields = ssm.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance);
SessionStateStoreData rqItem = null;
SessionStateStoreProviderBase store = null;
FieldInfo rqIdField = null, rqLockIdField = null, rqStateNotFoundField = null;
foreach (var field in fields)
{
if (field.Name.Equals("_store")) store = (SessionStateStoreProviderBase)field.GetValue(ssm);
if (field.Name.Equals("_rqId")) rqIdField = field;
if (field.Name.Equals("_rqLockId")) rqLockIdField = field;
if (field.Name.Equals("_rqSessionStateNotFound")) rqStateNotFoundField = field;
if ((field.Name.Equals("_rqItem")))
{
rqItem = (SessionStateStoreData)field.GetValue(ssm);
}
}
var lockId = rqLockIdField.GetValue(ssm);
if ((lockId != null) && (oldId != null))
{
store.ReleaseItemExclusive(Context, oldId, lockId);
store.RemoveItem(Context, oldId, lockId, rqItem);
}
rqStateNotFoundField.SetValue(ssm, true);
rqIdField.SetValue(ssm, newId);
}
}
Please keep in mind that I am developing in a Sitefinity web application.
Every time my application hits LoginCompletedEventVerification during a successful login, Context comes up as null. Now, I initially wanted to add this snippet to the Sitefinity LoginWidget, but making that happen is a whole other story.
I did not include it in the code sample, but I do have Session_Start firing to create my application's "shopping cart." I am just trying to create a new SessionID for the cart after authentication.
Is there a reason I cannot get a value for Context during this event?
Thanks in advance. I appreciate any suggestions or criticism!
EDIT: Sitefinity knowledge base article where I got my Bootstrapper_Initialized code

I did not include it in the code sample, but I do have Session_Start
firing to create my application's "shopping cart." I am just trying to
create a new SessionID for the cart after authentication.
Nooooo. Forget about accessing HttpContext in the Application_Start event.
Alternatively you could do that in Application_BeginRequest:
private static object syncRoot = new object();
private static bool initialized = false;
public void Application_BeginRequest(object sender, EventArgs e)
{
if (!initialized)
{
lock (syncRoot)
{
if (!initialized)
{
// Do your stuff here with HttpContext
initialized = true;
}
}
}
}
Another thing you should be aware of is that HttpContext will not be available in any background threads that you might have spawned and in which the HTTP request has already finished executing. So you should be extremely careful where you are trying to access this HttpContext.

The LoginCompletedEvent event is synchronous - it is not fired in a background thread, it is rather part of the authentication request. You can access the current context by either directly calling HttpContect.Current or since you are in the context of a Sitefinity application you can use the Sitefinity wrapper for the current context:
var currentContext = SystemManager.CurrentHttpContext;

Related

EFCore - How to run simple query on a loop?

I'm working on a project where users can queue up actions to happen in the future. Each future action is saved in the database. I'm trying to find a way to get all the actions that have already passed and act on them. Currently I'm doing this:
public class TaskingManager
{
private static readonly System.Timers.Timer RefreshEventsLoop = new(1000);
public void Initialize()
{
RefreshEventsLoop.Elapsed += RefreshEventsLoop_Elapsed;
RefreshEventsLoop.AutoReset = false;
RefreshEventsLoop.Start();
}
private void RefreshEventsLoop_Elapsed(object? sender, System.Timers.ElapsedEventArgs e)
{
RefreshEventsLoop.Enabled = false;
ProcessEventsQueue();
RefreshEventsLoop.Enabled = true;
}
private void ProcessEventsQueue()
{
var timeNow = DateTime.UtcNow;
var context = new GalaxyDbContext(_dbOptions);
var dbFunctions = new DatabaseFunctions(context);
var eventsToProcess = context.FutureEvents
.Where(futureEvent => futureEvent.TriggerTime <= timeNow)
.ToList();
if (eventsToProcess.Any())
{
context.FutureEvents.RemoveRange(eventsToProcess);
context.SaveChanges();
foreach (var pastEvent in eventsToProcess)
{
_messageMap[pastEvent.MessageType].Invoke(dbFunctions).Execute(pastEvent);
}
}
else
{
dbFunctions.CreateFutureScienceTask();
}
}
}
This seems to work ok. But the problem is that after the app has been running for a while, I can see the LINQ part is taking up a huge amount of memory:
524MB used
And if I leave it running for a few days then it's up in the gigs.
I'm guessing running this query every second is wasteful on resources. But I don't know of a better way to do this. Is there a way to continuously check the database for something like this?
The first thing i can see is that you are not disposing the databasecontextt afer you used it.
Read this for more info about entityframework context lifetime.
To properly dispose it use a using statement.
using (var context = new GalaxyDbContext(_dbOptions))
{
//your code that uses the context
}
Or with new using syntax:
using (var context = new GalaxyDbContext(_dbOptions));
//your code that uses the context
Right know the problem could be that you create a context everytime you call the function and never dispose it and it still keeps references to the data etc..

HttpContext.Current.Cache clears after while

I'm using HttpContext cache in a console application and after a while(2 or 3 hours) HttpContext cache is removed automatically. How to stop clearing cache??
private List<Model.CacheModel> _CompleteList = null;
public List<Model.CacheModel> CompleteList
{
get
{
if (_CompleteList == null)
{
_CompleteList = (HttpContext.Current.Cache["CompleteList"] as List<Model.CacheModel>);
if (_CompleteList == null)
{
_CompleteList = new List<Model.CacheModel>();
HttpContext.Current.Cache.Insert("CompleteList", _CompleteList);
}
}
return _CompleteList;
}
set
{
HttpContext.Current.Cache.Insert("CompleteList", _CompleteList);
}
}
This is where I use this property
public void GetControl(List<Model.CacheModel> List)
{
var CahcedList = (HttpContext.Current.Cache["CompleteList"] as List<Model.CacheModel>);
if (CahcedList == null)
{
HttpContext.Current.Cache["CompleteList"] = List;
}
else
{
if (CahcedList.LastOrDefault().Time != List.LastOrDefault().Time)
{
CahcedList.Remove(CahcedList.FirstOrDefault());
CahcedList.Add(List.LastOrDefault());
Clients.Others.broadcastAll(
JsonConvert.SerializeObject(List.LastOrDefault()));
}
}
}
According to MSDN, the cache will be cleared on the following scenarios:
The code manually clears an entry.
By using the Remove method of the Cache object.
The cache entry expires.
By using the absoluteExpiration or slidingExpiration parameters of the Add and Insert methods of the Cache object.
3.The host process ends (application or IIS reset, application pool recycle, etc).

Blocking dangerous IPs for accessing a resource

Environment
My IIS host an WebApp with WebService resources.
...
myWebService.asmx
myWebService.svc
...
Problem
Same bad guys, try to block server accessing the public resources with theirs bots.
Applied solution
I Build a filter:
public class BadGuysFilter
{
private class BadGuy
{
public BadGuy()
{
Visits = 0;
FirstSuspiciousVisit = DateTime.Now;
}
public int Visits;
public DateTime FirstSuspiciousVisit;
}
private static volatile Dictionary<string, BadGuy> _blackList = new Dictionary<string, BadGuy>();
private static int _visitsLimit = 10;
private static int _minutsLimit = 10;
private static int _removeFromBlackListMinutesLimit = 30;
public static void Init(int visitsLimit = 10, int minutsLimit = 10, int removeFromBlackListMinutesLimit = 30)
{
_visitsLimit = visitsLimit;
_minutsLimit = minutsLimit;
_removeFromBlackListMinutesLimit = removeFromBlackListMinutesLimit;
}
public static bool IsBadGuy()
{
return IsBadGuy(HttpContext.Current.Request.UserHostAddress);
}
public static bool IsBadGuy(string ip)
{
if (HttpContext.Current.Request.IsAuthenticated /*|| HttpContext.Current.Request.HttpMethod.ToUpper() == "POST"*/)
return false;
if (_blackList.Keys.Any(k => k == ip))
{
_blackList[ip].Visits++;
if (_blackList[ip].FirstSuspiciousVisit < DateTime.Now.AddMinutes(-_removeFromBlackListMinutesLimit))
_blackList.Remove(ip);
else if (_blackList[ip].FirstSuspiciousVisit < DateTime.Now.AddMinutes(-_minutsLimit))
{
_blackList[ip].Visits = 0;
_blackList[ip].FirstSuspiciousVisit = DateTime.Now;
}
else if (_blackList[ip].Visits > _visitsLimit)
{
_blackList[ip].FirstSuspiciousVisit = DateTime.Now;
return true;
}
}
else
_blackList.Add(ip, new BadGuy());
return false;
}
public static void Punish()
{
var res = HttpContext.Current.Response;
res.Clear();
res.StatusCode = 429;
res.StatusDescription = "TOO MANY REQUESTS: Your application is sending too many simultaneous requests.";
res.End();
}
}
Use filter in Global.asax
void Application_BeginRequest(object sender, EventArgs e) {
if(BadGuysFilter.IsBadGuy())
BadGuysFilter.Punish();
// do stuff //
}
void Application_EndRequest(object sender, EventArgs e) {
var app = (HttpApplication)sender;
if (app.Context.Response.StatusCode == 429) // "TOO MANY REQUESTS"
return;
// do stuff //
}
Question
Is this an enough safe solution? Or maybe there is another way?
Edite:
"don't block at the resource itself. block farther upstream, e.g. at the firewall. – Marc B"
Yes, you're right. This is final solution, but before apply it i need intermediate solution to defend my server. I forgot to mention this thing. – Artiom
You can use IIS Dynamic IP restriction module (from Microsoft):
http://www.iis.net/downloads/microsoft/dynamic-ip-restrictions
I agree with the comments above. You need to block ddos further upstream otherwise you application is still going to be servicing each request.
This type of approach appears to lack any persistence. Therefore, when they bombard your system and you recycle the app pools, it will reset. On the other hand, the firewall apprach lacks the flexibility to remove after a certain time...I think.
That said, if you need to handle suspicious requests of a different nature such as too many request to the login page but not the home page or something then this could be a viable solution.
It is really just considering all of your goals and understanding the risks and limitations.

Asynchronous call in web service

I'm using web service for my wp7 app and i have a difficulty in finding out whether the asynchronous call to the service returns the value or not. i have a validation depends on the response(result). The following the code snippet for calling the web service and appropriate changes that should be made to the UI.
private void TLP_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
objevnt.indexChanged(1, lpcountry.SelectedIndex, "depart");
if(objevnt.CName.Count>0)
lpcity.ItemsSource = objevnt.GetCityDetails();
}
public void indexChanged(int Travel,int index,string journey)
{
string slCountry = null;
switch (Travel)
{
case 1:
slCountry = lstCtryDetails.lstCtrylist[index].countryId.ToString();
//= "depart";
travelMode = journey;
break;
case 2:
slCountry = lstCtryDetails.lstCtrylist[index].countryId.ToString();
travelMode = journey;
break;
case 3:
slCountry = lstCtryDetails.lstCtrylist[index].countryId.ToString();
travelMode = journey;
break;
}
GetCities = "http://Solutions/mobileservice/Citylist/countrycode/" + slCountry;
WebClient myClientcity = new WebClient();
myClientcity.DownloadStringAsync(new Uri(GetCities, UriKind.RelativeOrAbsolute));
myClientcity.DownloadStringCompleted += new DownloadStringCompletedEventHandler(myClientcity_DownloadStringCompleted);
}
private void myClientcity_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
string _Countries = null;
if (e.Error == null)
{
_Countries = e.Result;
parseCtry(_Countries);
}
}
private void parseCtry(string xml)
{
XDocument myXdoc = XDocument.Load(new StringReader(xml));
IEnumerable<XElement> lstElm = myXdoc.Descendants("GetCityList");
lstCtryDetails.lstCitylist.Clear();
foreach (XElement ele in lstElm.Elements())
{
if (ele.Name.ToString() != "Message")
{
// Fetch t Details
if (!ele.IsEmpty && ele.Name.ToString() == "City")
{
lstCtryDetails.lstCitylist.Add(new cityList() { CityId = ele.Element("CityCode").Value, CityName = ele.Element("CityName").Value, CityLatitude = ele.Element("Latitude").Value, CityLongitude = ele.Element("Longitude").Value });
CName.Add(ele.Element("CityName").Value);
//Countchk = true;
}
}
}
lsCity = lstCtryDetails.lstCitylist;
//chkloop = true;
}
public List<cityList> GetCityDetails()
{
if (lsCity.Count > 0)
return lsCity;
return null;
}
Now i need to get the list of values from the getcitydetails() method. but that is reurning null due to asynchronous call. how to get the count of list, to do appropriate validations. Thanks in advance.
You're setting the ItemsSource potentially before your WebClient has returned it's result, nor had chance to call parseCtry.
If you move:
lpcity.ItemsSource = objevnt.GetCityDetails();
to the end of parseCtry (i.e. where the comment //chkloop = true; is) then it will evaluate to have the correct count - but you may run into cross-thread UI access issues, but you should be able to check with something like (at the start of DownloadStringCompleted):
if (Dispatcher.CheckAccess())
Dispatcher.BeginInvoke(new DownloadStringCompletedEventHandler(myClientcity_DownloadStringCompleted), xml) // put us back on the UI thread if required
You may be better off changing the type of lsCity to be an ObservableCollection<cityList> and binding to it.
Have you tried adding the callback before performing the webrequest?
myClientcity.DownloadStringCompleted += new DownloadStringCompletedEventHandler(myClientcity_DownloadStringCompleted);
myClientcity.DownloadStringAsync(new Uri(GetCities, UriKind.RelativeOrAbsolute));
=== Updated ===
From your comments I think I understand that problem. What you want is to data bind an ObservableCollection<T> to your UI element lpCity. If for instance if lpCity was data bound to lsCity (implementing ObservableCollection<T>), once lpCity is updated via a asynchronous web request, the UI element will update automatically.
I would write out a code skeleton for you, I'm away from my Windows PC.

Object reference not set to an instance when modifying an existing cookie in code behind

In the line "Response.Cookies...", I get an object reference not set to an instance of an object. Is there a way to fix this and use a timer in my ASPX code behind?
protected void Page_Load(object sender, EventArgs e)
{
object o = new object();
TimerCallback timercallback = new TimerCallback(StartCallback);
System.Threading.Timer timer = new Timer(timercallback, o, 0, 50000);
if (are.WaitOne())
{
Response.Redirect("Default.aspx");
}
}
public void StartCallback(object o)
{
//Request.Cookies["haspassed?"].Value = "";
Response.Cookies["haspassed?"].Expires = System.DateTime.Now.AddMonths(-1);
are.Set();
}
Thanks
iirc the new thread which StartCallback is going to operate in isn't going to have an HTTPContext, so the nullpointer is that Response does not exist. Why not pass it the context as "o"?
So I cast o to a HttpContext object? I'll give that a go.
I'm using a C# timer out of preference of server side coding than JS, really.
It's an odd problem; Response (according to Reflector) is:
[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public HttpResponse Response
{
get
{
if (this._response == null)
{
throw new HttpException(SR.GetString("Response_not_available"));
}
return this._response;
}
}
So it can't return null - you'd get an HttpException instead.
Likewise, Cookies is:
public HttpCookieCollection Cookies
{
get
{
if (this._cookies == null)
{
this._cookies = new HttpCookieCollection(this, false);
}
return this._cookies;
}
}
So you wouldn't get null there either.
The Cookies' indexer? Nope:
public HttpCookie Get(string name)
{
HttpCookie cookie = (HttpCookie) base.BaseGet(name);
if ((cookie == null) && (this._response != null))
{
cookie = new HttpCookie(name);
this.AddCookie(cookie, true);
this._response.OnCookieAdd(cookie);
}
return cookie;
}
So I thought, the only thing we have left, is inside the Cookies indexer, if this._response == null, the cookie setting will not happen and this will return null. But that can't happen either since _cookies is only ever in that line we saw earlier, which calls a constructor which is the only place where _response is set - set to the correct HttpRespones, never null.
In conclusion, I've dug deep in there and can't see any way for the Response.Cookies["haspassed?"].Expires setter to ever throw a NullReferenceException.

Categories

Resources