Simple counter increment in Asp.net Core - c#

In my controller, I want to count the number of bad attempts to login.
else
{
// Increment counter by 1
// check if counter == 3
// ban user
logonAttempt++;
if (logonAttempt >= MAX_LOGON_ATTEMPT)
{
ModelState.AddModelError("", "This account has been locked. Please contact the help desk for further support.");
} else
{
ModelState.AddModelError("", "You have entered an invalid username or password.");
}
}
Every time the user clicks "submit" and the code enters into this else statement, the logonAttempt resets to 0.
Is there anyway to prevent it from resetting? for the users session?

I think you are misunderstanding some stuff.
You can count in the session, but the new architecture patterns tend to work as session less.
The lifecycle should be, request, instantiate something really small, respond, and then release the instance to start working lightweight.
One thing you can do is just update the cookie stored with the validation token or method you are using for login.
My advice is just to check this framework, really flexible, where all these concerns are already solved.
https://learn.microsoft.com/en-us/aspnet/core/security/authentication/identity?view=aspnetcore-3.1&tabs=visual-studio

Maybe you can do it in a way like this:
// my class
private static XDic<DateTime, XDic<string, int>> daily_reg_attemps = new XDic<DateTime,XDic<string, int>>();
const int limit = 20;
public bool is_banned(string key,HttpRequestMessage request)
{
//handle attempt monitoring
var today = DateTime.Today.Date;
if (!daily_reg_attemps.ContainsKey(today))
daily_reg_attemps.Add(today, new XDic<string, int>());
var reg_attemps = daily_reg_attemps[today];
//handle attempts
var ip = GetClientIp(request);
if (!reg_attemps.ContainsKey(ip)) reg_attemps.Add(ip, 0);
if (!reg_attemps.ContainsKey(key)) reg_attemps.Add(key, 0);
//prevent localhost
if (!request.RequestUri.Host.Contains("localhost"))
{
reg_attemps[ip]++;
reg_attemps[key]++;
}
return (reg_attemps[ip] > limit || reg_attemps[key] > limit);
}
//my custom dictionary
public class XDic<TKey, TValue> : Dictionary<TKey, TValue>
{
public virtual void Add(TKey key, TValue value, bool updateIfExist = true)
{
if (key == null)
{
throw new ArgumentException("Key parameter is Null.");
}
if (base.ContainsKey(key))
{
if (updateIfExist)
{
base[key] = value;
}
else {
throw new ArgumentException("Error")
}
}
else {
base.Add(key, value);
}
}

Related

How to get the latest ID from Firebase console from Untiy

I have a Unity project with Firebase for google Authentication. I am storing user information in a realtime database. They are stored as:
UnityProject
1->
Name: "Something"
Email: "Something"
2->
Name: "some other thing"
Email: "Something else"
Now, these 1,2 are to be given by me (to be used as a primary key). I would start by giving the first user ID 1 and the second used ID 2 and so on.
But I need to get back from the firebase the last ID which was stored. For example,
idToInsert = GetLastUsedID() + 1;
I have used this code but it doesn't work. The screen just freezes until I force close Unity.
public int GetLastUsedID()
{
int currentID = 1;
bool continueSearch = true;
while (continueSearch)
{
FirebaseREST.DatabaseReference reference = FirebaseREST.FirebaseDatabase.Instance.GetReference(""+currentID);
string value = "";
currentID++;
reference.GetValueAsync(10, (res) =>
{
if (res.success)
{
value = res.data.GetRawJsonValue();
Debug.Log("Success fetched data : " + value);
if(value == "")
{
continueSearch = false;
Debug.Log(currentID);
}
}
else
{
Debug.Log("Fetch data failed : " + res.message);
continueSearch = false;
}
});
}
return currentID;
}
Basically I am just trying to iterate from 1 till whenever I get the empty string. The empty string means no data exists under that ID.
I'm not familiar with FirebaseREST (I would recommend using the official Firebase plugin if you're able, it does much more than just call REST endpoints), but I think I can see your issue.
GetValueAsync likely runs asynchronously in the background. So the logic inside the block (the (res)=> part) is firing off many times (basically infinitely with that while loop). Then, depending on how this is implemented, either continueSearch never goes to false because it isn't marked volatile or the callback logic never gets a chance to run (say if FirebaseREST tries to dispatch to the main thread, which is locked in an infinite while loop).
If GetValueAsync returns a Task, you can use some of the tips I cover in this article. My recommendation would be to try to use async/await, so your logic would look more like:
async public int GetLastUsedID()
{
volatile int currentID = 1;
volatile bool continueSearch = true;
while (continueSearch)
{
FirebaseREST.DatabaseReference reference = FirebaseREST.FirebaseDatabase.Instance.GetReference(""+currentID);
string value = "";
currentID++;
await reference.GetValueAsync(10, (res) =>
{
if (res.success)
{
value = res.data.GetRawJsonValue();
Debug.Log("Success fetched data : " + value);
if(value == "")
{
continueSearch = false;
Debug.Log(currentID);
}
}
else
{
Debug.Log("Fetch data failed : " + res.message);
continueSearch = false;
}
});
}
return currentID;
}
This is probably not the case, in which case you'll probably want to turn this into a recursive call. You'd want some function like:
public void GetLastUsedID(currentId)
{
FirebaseREST.DatabaseReference reference = FirebaseREST.FirebaseDatabase.Instance.GetReference(""+currentID);
reference.GetValueAsync(10, (res) =>
{
if (res.success)
{
value = res.data.GetRawJsonValue();
Debug.Log("Success fetched data : " + value);
if(value == "")
{
continueSearch = false;
Debug.Log(currentID);
}
else
{
// recurse
GetLastID(currentId+1);
}
}
else
{
Debug.Log("Fetch data failed : " + res.message);
continueSearch = false;
}
});
}
You will have to figure out how to pass in your own callback to bubble a success or failure like this (exercise to the reader).
Finally, I would be a little cautious with what you're doing entirely. If you're authenticating users, I'd recommend using Firebase Authentication which ties directly into Realtime Database. At most you'd only store user id's in there, and use security rules to ensure that only that user can write into it (for instance). By using Firebase Authentication to manage user data and tying that to RTDB rules, you avoid the same mistakes this author made.

can i use the PromptDialog.choice continuously to ask many related infomation in botframework

I want to ask many questions continuously to user, and each question depends on the choose of the question before. I want to use PromptDialog.Choice() to implement it but i find if i do it like this, since the second user info, will still invoke the first callback function, and i don't know how to jump out from the function.
public void getchoose(IDialogContext context)
{
List<string> option_provide = null;
bool if_find = true;
foreach (var i in question.GetSortedProperties())
{
nowchoice = i;
if (!question.select<test_tableinfo>(i.Name, (string)i.GetValue(question), allOptions, out allOptions, out option_provide))
{
if (allOptions.Count() == 1)
{
context.PostAsync(allOptions.First().answer);
if_find = false;
context.Wait(MessageReceived);
}
if (option_provide.Count() < 1)
{
context.PostAsync("请联系客服");
if_find = false;
}
else if (option_provide.Count() == 1)
{
i.SetValue(question, option_provide[0]);
question.select(i.Name, (string)i.GetValue(question), allOptions, out allOptions, out option_provide);
}
else
{
PromptDialog.Choice<string>(context, AfterChoose, option_provide, "选择你需要的"+i.Name, "retry", 2);
if_find = false;
break;
}
}
}
if (if_find)
{
foreach (var i in allOptions)
{
context.PostAsync(i.answer);
}
context.Wait(MessageReceived);
}
}
and the callback function afterchoose
public async Task AfterChoose(IDialogContext context, IAwaitable<string> choice)
{
try
{
string temp = await choice;
if (temp != null)
nowchoice.SetValue(question, temp);
}
catch (Exception)
{
}
context.Reset();
getchoose(context);
}
i use reflection here to get the order of variables but it is not important for this question
I believe what you are looking for is already part of the Bot Framework. FormFlow is a feature that allows you to construct a model of the data that you wish to gather from the user and then ask a series of questions, which can be branched in necessary depending upon answers.
Check out the FormFlow documentation on the Bot Framework site.

Loop through list tuples and add if there is no match

i am writing a game server in C#,every time someone sends the login message with his username i add him to a list of tuples with ID,IPENDPOINT,USERNAME.
I want to check if the client doesn't have same username as an already connected client,so i tried to loop through the list and get list.Item3 'which is username' and use String.Equals(list.Item3, username) to check if the username exists.
My problem is when i loop,my code compares to only the first tuple in the list,if it was true then send a error message,if not then send accept message and when the list has +1 client it only compares to the first also and accept even if the tuple number 2 or 3... has that username.
i tried many ways,this is the last code i tried:
for (int i = 0; i < clientsInfoList.Count; i++)
{
bool isUsed;
if (String.Equals(clientsInfoList[i].Item3, Username))
{
isUsed = true;
}
if (isUsed)
{
Console.WriteLine("Username is already used!");
udpServer.Send(Encoding.ASCII.GetBytes("REFUSED"), Encoding.ASCII.GetByteCount("REFUSED"), remoteEP);
break;
}
else if(!isUsed)
{
clientsInfoList.Add(new Tuple<int, IPEndPoint, string>(id, remoteEP, Username));
Console.WriteLine("Username has been added to the list :)");
udpServer.Send(Encoding.ASCII.GetBytes("ACCEPTED"), Encoding.ASCII.GetByteCount("ACCEPTED"), remoteEP);
}
}
i tried many other ways but i couldn't achieve the verification.
Thanks in advance.
You put everything in a loop. Why? You should use the loop only to check whether the username is taken or not and send your messages outside of it.
First of all you'd like to force your loop to work only as long as it should. You can do it by declaring isUsed before it and adding it to the condition. Then, in the loop, you only check whether the name is taken and change the value of your variable. The loop will either iterate through all the clients or end when it encounters the first name that matches your condition. When the loop is over, you should decide which command you send basing on the results.
bool isUsed = false;
for (int i = 0; i < clientsInfoList.Count && !isUsed; i++)
{
isUsed = String.Equals(clientsInfoList[i].Item3, Username);
}
if (isUsed)
{
Console.WriteLine("Username is already used!");
udpServer.Send(Encoding.ASCII.GetBytes("REFUSED"), Encoding.ASCII.GetByteCount("REFUSED"), remoteEP);
}
else
{
clientsInfoList.Add(new Tuple<int, IPEndPoint, string>(id, remoteEP, Username));
Console.WriteLine("Username has been added to the list :)");
udpServer.Send(Encoding.ASCII.GetBytes("ACCEPTED"), Encoding.ASCII.GetByteCount("ACCEPTED"), remoteEP);
}
You can just do
var isUsed = clientsInfoList.Any(info => info.Item3 == Username);
if (isUsed)
{
// ...
}
else
{
// ...
}
I assume both Item3 (the T3 of Tuple<T1, T2, T3>) and Username have compile-time type string.
Why would you put the entire logic in the for loop ? Place only the below code inside for loop.
bool isUsed;
if (String.Equals(clientsInfoList[i].Item3, Username))
{
isUsed = true;
}
It will now verify all elements in the tuple and perform the remaining logic.
You're going about this the wrong way entirely, first thing I would do if I was you, would be to get rid of the Tuples, create a class which contains the 3 properties that you need.
Also in such circumstances try to use a HashSet instead of a list, they're better optimized and will help your game run faster if you have a large collection of clients.
The cleanest way to achieve what you're asking is by using LINQ, here's how I would rewrite the code that you've written above.
public class Game
{
public Game()
{
this.Clients = new HashSet<Clients>();
}
public HashSet<Client> Clients { get; set;}
public void OnClientConnect(Client newClient)
{
// Are there any clients with the username that the newUser is attempting to use?
bool usernameIsFree = this.Clients.Any(clients => clients.UserName == newClient.UserName);
if (usernameIsFree)
{
this.Clients.Add(newClient);
Console.WriteLine("Username has been added to the list :)");
// UDP stuff here...
return;
}
Console.WriteLine("Username is already used!");
// UDP stuff here
}
}
public class Client
{
public int ClientId { get; set; }
public IPEndPoint IPEndPoint { get; set; }
public string UserName { get; set; }
}

Retrieve call forwarding rules of a Lync client with server-side technologies (UCMA or MSPL)

How can I retrieve the call forwarding rules (routing) of a Lync client in a Managed SIP Application (serverside technologies like MSPL or UCMA)? The only thing I found is an Article on how you can do it clientside with the Lync SDK.
Also this Answer and this MSDN Article and this Question seem to indicate that it does work but I need this setting at a specific moment (if the User is online or not) and not as soon as he logs into his Lync account and publishes his presence info, as seen in link #1. Also it is necessary to get this for any client without creating an UserEndpoint first. So it would be best if this is possible with an ApplicationEndpoint (or another method).
As far as I found out, it should be possible to retrieve the forwarding settings from the presence metadata, but I do not get this information.
var categories = new string[] {
"state",
//"routing" // ?
};
var asyncresult = presenceSvc.BeginPresenceQuery(sips, categories, null, null, null);
var result = presenceSvc.EndPresenceQuery(asyncresult).ToList();
You cannot do it with an ApplicationEndpoint. You must have an UserEndpoint.
However, you can create a UserEndpoint who just need the CollaborationPlateform and the SipUser and not any passwords.
For my application, I decompiled SEFAUtil.exe via ILSpy to understand how they did in their programs. I advise you to take a look at it.
This is my technique to make it works:
1/ Creation of the UserEndPoint
When creating the user endpoint you have to subscribe for this presence to get the information even if is not connected
userEndpoint.LocalOwnerPresence.BeginSubscribe(null, null);
2/ Subscribe to PresenceNotificationReceived Event
userEndpoint.LocalOwnerPresence.PresenceNotificationReceived += OnCategoryNotificationReceived;
private static void OnCategoryNotificationReceived(object sender, LocalPresentityNotificationEventArgs e)
{
// Here you get the PresenceCategory and all the data of the user
foreach (PresenceCategoryWithMetaData current in e.AllCategories)
{
if (current.Name == "routing" && current.ContainerId == 0 && current.InstanceId == 0L)
// Creation of your Routing, I stock it in a Property
_routingCategory = new Routing(current);
}
// I set my event to continue my main thread
_routingCategoryUpdated.Set();
}
3/ Display the information you want
// Wait until you get the information of the user
if (!_routingCategoryUpdated.WaitOne(10000))
{
Console.WriteLine("TimeOut Getting Informations");
return;
}
// Just display all the data you can need
else
{
Console.WriteLine($"User Aor: {userEndPointTarget.OwnerUri}");
Console.WriteLine($"Display Name: {userEndPointTarget.OwnerDisplayName}");
Console.WriteLine($"UM Enabled: {userEndPointTarget.UmEnabled}");
Console.WriteLine($"Simulring enabled: {_routingCategory.SimultaneousRingEnabled}");
if (_routingCategory.SimultaneousRingEnabled && _routingCategory.SimultaneousRing != null)
{
foreach (string time in _routingCategory.SimultaneousRing)
{
Console.WriteLine($"Simul_Ringing to: {time}");
}
}
if (_routingCategory.DelegateRingEnabled)
{
if (_routingCategory.SkipPrimaryEnabled)
{
Console.Out.Write("Forwarding calls to Delegates: ");
}
else if (_routingCategory.UserWaitTimebeforeTeamOrDelegates.TotalSeconds > 0.0)
{
Console.Out.Write($"Delay Ringing Delegates (delay:{ _routingCategory.UserWaitTimebeforeTeamOrDelegates.TotalSeconds} seconds): ");
}
else
{
Console.Out.Write("Simultaneously Ringing Delegates: ");
}
foreach (string delegateCurrent in _routingCategory.Delegates)
{
Console.Out.Write($"{delegateCurrent} ");
}
Console.Out.WriteLine();
}
else if (_routingCategory.TeamRingEnabled)
{
if (_routingCategory.UserWaitTimebeforeTeamOrDelegates.TotalSeconds > 0.0)
{
Console.Out.Write($"Delay Ringing Team (delay:{_routingCategory.UserWaitTimebeforeTeamOrDelegates.TotalSeconds} seconds). Team: ");
}
else
{
Console.Out.Write("Team ringing enabled. Team: ");
}
foreach (string currentTeam in _routingCategory.Team)
{
Console.Out.Write($"{currentTeam} ");
}
Console.Out.WriteLine();
}
else if (_routingCategory.CallForwardToTargetsEnabled)
{
if (_routingCategory.CallForwardingEnabled)
{
Console.Out.WriteLine($"Forward immediate to: {_routingCategory.CallForwardTo}");
}
else
{
Console.Out.WriteLine($"User Ring time: {_routingCategory.UserOnlyWaitTime}");
Console.Out.WriteLine($"Call Forward No Answer to: {_routingCategory.CallForwardTo[0]}");
}
}
else if (userEndPointTarget.UmEnabled)
{
Console.Out.WriteLine($"User Ring time: {_routingCategory.UserOnlyWaitTime}");
Console.Out.WriteLine("Call Forward No Answer to: voicemail");
}
else
{
Console.Out.WriteLine("CallForwarding Enabled: false");
}

What is the best way to lock cache in asp.net?

I know in certain circumstances, such as long running processes, it is important to lock ASP.NET cache in order to avoid subsequent requests by another user for that resource from executing the long process again instead of hitting the cache.
What is the best way in c# to implement cache locking in ASP.NET?
Here's the basic pattern:
Check the cache for the value, return if its available
If the value is not in the cache, then implement a lock
Inside the lock, check the cache again, you might have been blocked
Perform the value look up and cache it
Release the lock
In code, it looks like this:
private static object ThisLock = new object();
public string GetFoo()
{
// try to pull from cache here
lock (ThisLock)
{
// cache was empty before we got the lock, check again inside the lock
// cache is still empty, so retreive the value here
// store the value in the cache here
}
// return the cached value here
}
For completeness a full example would look something like this.
private static object ThisLock = new object();
...
object dataObject = Cache["globalData"];
if( dataObject == null )
{
lock( ThisLock )
{
dataObject = Cache["globalData"];
if( dataObject == null )
{
//Get Data from db
dataObject = GlobalObj.GetData();
Cache["globalData"] = dataObject;
}
}
}
return dataObject;
There is no need to lock the whole cache instance, rather we only need to lock the specific key that you are inserting for.
I.e. No need to block access to the female toilet while you use the male toilet :)
The implementation below allows for locking of specific cache-keys using a concurrent dictionary. This way you can run GetOrAdd() for two different keys at the same time - but not for the same key at the same time.
using System;
using System.Collections.Concurrent;
using System.Web.Caching;
public static class CacheExtensions
{
private static ConcurrentDictionary<string, object> keyLocks = new ConcurrentDictionary<string, object>();
/// <summary>
/// Get or Add the item to the cache using the given key. Lazily executes the value factory only if/when needed
/// </summary>
public static T GetOrAdd<T>(this Cache cache, string key, int durationInSeconds, Func<T> factory)
where T : class
{
// Try and get value from the cache
var value = cache.Get(key);
if (value == null)
{
// If not yet cached, lock the key value and add to cache
lock (keyLocks.GetOrAdd(key, new object()))
{
// Try and get from cache again in case it has been added in the meantime
value = cache.Get(key);
if (value == null && (value = factory()) != null)
{
// TODO: Some of these parameters could be added to method signature later if required
cache.Insert(
key: key,
value: value,
dependencies: null,
absoluteExpiration: DateTime.Now.AddSeconds(durationInSeconds),
slidingExpiration: Cache.NoSlidingExpiration,
priority: CacheItemPriority.Default,
onRemoveCallback: null);
}
// Remove temporary key lock
keyLocks.TryRemove(key, out object locker);
}
}
return value as T;
}
}
Just to echo what Pavel said, I believe this is the most thread safe way of writing it
private T GetOrAddToCache<T>(string cacheKey, GenericObjectParamsDelegate<T> creator, params object[] creatorArgs) where T : class, new()
{
T returnValue = HttpContext.Current.Cache[cacheKey] as T;
if (returnValue == null)
{
lock (this)
{
returnValue = HttpContext.Current.Cache[cacheKey] as T;
if (returnValue == null)
{
returnValue = creator(creatorArgs);
if (returnValue == null)
{
throw new Exception("Attempt to cache a null reference");
}
HttpContext.Current.Cache.Add(
cacheKey,
returnValue,
null,
System.Web.Caching.Cache.NoAbsoluteExpiration,
System.Web.Caching.Cache.NoSlidingExpiration,
CacheItemPriority.Normal,
null);
}
}
}
return returnValue;
}
Craig Shoemaker has made an excellent show on asp.net caching:
http://polymorphicpodcast.com/shows/webperformance/
I have come up with the following extension method:
private static readonly object _lock = new object();
public static TResult GetOrAdd<TResult>(this Cache cache, string key, Func<TResult> action, int duration = 300) {
TResult result;
var data = cache[key]; // Can't cast using as operator as TResult may be an int or bool
if (data == null) {
lock (_lock) {
data = cache[key];
if (data == null) {
result = action();
if (result == null)
return result;
if (duration > 0)
cache.Insert(key, result, null, DateTime.UtcNow.AddSeconds(duration), TimeSpan.Zero);
} else
result = (TResult)data;
}
} else
result = (TResult)data;
return result;
}
I have used both #John Owen and #user378380 answers. My solution allows you to store int and bool values within the cache aswell.
Please correct me if there's any errors or whether it can be written a little better.
I saw one pattern recently called Correct State Bag Access Pattern, which seemed to touch on this.
I modified it a bit to be thread-safe.
http://weblogs.asp.net/craigshoemaker/archive/2008/08/28/asp-net-caching-and-performance.aspx
private static object _listLock = new object();
public List List() {
string cacheKey = "customers";
List myList = Cache[cacheKey] as List;
if(myList == null) {
lock (_listLock) {
myList = Cache[cacheKey] as List;
if (myList == null) {
myList = DAL.ListCustomers();
Cache.Insert(cacheKey, mList, null, SiteConfig.CacheDuration, TimeSpan.Zero);
}
}
}
return myList;
}
This article from CodeGuru explains various cache locking scenarios as well as some best practices for ASP.NET cache locking:
Synchronizing Cache Access in ASP.NET
I've wrote a library that solves that particular issue: Rocks.Caching
Also I've blogged about this problem in details and explained why it's important here.
I modified #user378380's code for more flexibility. Instead of returning TResult now returns object for accepting different types in order. Also adding some parameters for flexibility. All the idea belongs to
#user378380.
private static readonly object _lock = new object();
//If getOnly is true, only get existing cache value, not updating it. If cache value is null then set it first as running action method. So could return old value or action result value.
//If getOnly is false, update the old value with action result. If cache value is null then set it first as running action method. So always return action result value.
//With oldValueReturned boolean we can cast returning object(if it is not null) appropriate type on main code.
public static object GetOrAdd<TResult>(this Cache cache, string key, Func<TResult> action,
DateTime absoluteExpireTime, TimeSpan slidingExpireTime, bool getOnly, out bool oldValueReturned)
{
object result;
var data = cache[key];
if (data == null)
{
lock (_lock)
{
data = cache[key];
if (data == null)
{
oldValueReturned = false;
result = action();
if (result == null)
{
return result;
}
cache.Insert(key, result, null, absoluteExpireTime, slidingExpireTime);
}
else
{
if (getOnly)
{
oldValueReturned = true;
result = data;
}
else
{
oldValueReturned = false;
result = action();
if (result == null)
{
return result;
}
cache.Insert(key, result, null, absoluteExpireTime, slidingExpireTime);
}
}
}
}
else
{
if(getOnly)
{
oldValueReturned = true;
result = data;
}
else
{
oldValueReturned = false;
result = action();
if (result == null)
{
return result;
}
cache.Insert(key, result, null, absoluteExpireTime, slidingExpireTime);
}
}
return result;
}
The accepted answer (recommending reading outside of the lock) is very bad advice and is being implemented since 2008. It could work if the cache uses a concurrent dictionary, but that itself has a lock for reads.
Reading outside of the lock means that other threads could be modifying the cache in the middle of read. This means that the read could be inconsistent.
For example, depending on the implementation of the cache (probably a dictionary whose internals are unknown), the item could be checked and found in the cache, at a certain index in the underlying array of the cache, then another thread could modify the cache so that the items from the underlying array are no longer in the same order, and then the actual read from the cache could be from a different index / address.
Another scenario is that the read could be from an index that is now outside of the underlying array (because items were removed), so you can get exceptions.

Categories

Resources