I am trying to display the number of times a method is called from my client windows form application. Below are how the service and client are defined.
In my log file I see the count is incremented per method call but I am not able to see the total count that I put in the list from my client form.
IOperator
{
SendMessage(string strMsgId, string strMessage);
[OperationContract]
List<int> GetCount();
}
[ServiceBehavior(Namespace = "http://X.org/MessageService/"]
Operator: IOperator
{
private List<Int32> TotalCount = new List<Int32>();
public static List<int> TotalCount
{
get { return _totalCount; }
set { _totalCount = value; }
}
SendMessage(string strMsgId, string strMessage)
{
if (strMsgId == "02")
{
lock (_lock)
{
++_count;
TotalCount.Add(_count);
}
string debugFileName = "C:\\Test.txt";
// Write to the file:
inboundMessageLog.WriteLine("{0}{1}", "Inbound Message:", strMessage.Substring(549, 27));
inboundMessageLog.WriteLine("{0}{1}", "count:", _count);
inboundMessageLog.WriteLine("{0}{1}", "Total Count:", TotalCount.Count);
result = 0;
}
}
public List<int> GetCount()
{
return TotalCount;
}
}
EDIT
I am trying to save that total count in some session per a given time and get that count in my text box.I want the total count regardless of the number of clients. TotalCount is static, defined as private static List _totalCount = new List(); with getter TotalCount.
I didn't explicitly defined the InstanceContextMode for the service and yes the totalcount is showing 0.
Client:
var clientA = new SendServiceReference.SendService();
Operator clientB = new Operator();
while ((DateTime.Now - startTime) <= timeoutSpan)
{
// Send request to external service and all the requests will be logged to my service since I don't have control over the external service.
sendMessageResult = clientA.SendMessageToExternalService("01", txtRequest.Text);
}
//display the total request received from client A for the give time span
responseCount.Text = clientB.GetCount().Count.ToString();
You don't indicate what binding you are using or if you've explicitly defined the InstanceContextMode for the service, but from the behavior you've described it sounds like it's the default PerSession, which creates a new instance of the service for each client.
What is most likely happening is that you are creating one client to send the messages, which is why you are seeing the counter incremented. You then create a second client (client2 = new Operator();, which creates another instance of the service, which means TotalCount is either 0 or null (since you don't indicate that you get an error, I'm going to guess that the count TotalCount is 0). In other words, you're no longer accessing/using the instance of the service that incremented the count, but an entirely new instance of the service with its own TotalCount field/property.
There are a few ways to resolve this, depending on what your requirements/needs are.
If you need the total count regardless of the number of clients, you can either make TotalCount static, or you can set the InstanceContextMode to Single. I would discourage using InstanceContextMode.Single as that can lead to scaling problems, and go with a static TotalCount.
If you need the total count by each client, then you will need to use the same client that made the 10 calls in the loop to make the call to GetCount(). For example:
Operator client1 = new Operator();
for (int i =0; i < 10; i++)
{
// Send your messages
}
responseCount.Text = client1.GetCount().Count.ToString();
There's an article on CodeProject that has illustrations of the 3 different InstanceContextModes that may be of use for you: Three ways to do WCF instance management
Related
I have a scenario, where I have a worker method (DoWork()) which is getting called by the web service continuously.
This worker method writes the data to a file using the (writeToFile()) and I need to write this to a file under 2 conditions
a) when the number of records reached in 500 OR
b) 2 minutes has been passed from the previous file been written
my sample code is as follows:
public override void DoWork()
{
//-- This worker method is called continuously by the webservice
List<string> list1 = new List<string>();
List<string> list2 = new List<string>();
int count =0;
//--- Some code that writes the RawData
list1.Add(rawData);
If(list1.Count<=500)
{
list2=list1;
count = WriteToFile(list2);
}
}
public static int WriteToFile(List<string> list)
{
//-- The writing of File Should happen when 500 records reached OR 2 mins passed.
// ---- Logic for writing the list file using the Streamwriter is working fine
}
I need a logic check if
500 records reached in the List OR
2 mins passed from the previous
file generated,
only then the file writing should happen.
Thanks
:)
To make it a little more readable, I'd use a little helper, here...
Time check:
class TimeCheck{
private TimeSpan timeoutDuration;
private DateTime nextTimeout;
// Default = 2 minutes.
public TimeCheck(): this(TimeSpan.FromMinutes(2))
{}
public TimeCheck( TimeSpan timeout ){
this.timeoutDuration= timeout;
this.nextTimeout = DateTime.Now + timeoutDuration;
}
public bool IsTimeoutReached => DateTime.Now >= nextTimeout;
public void Reset(){
nextTimeout = DateTime.Now + timeoutDuration;
}
}
Usage:
// on class level
const int MAXITEMS = 500;
private Lazy<TimeCheck> timecheck = new Lazy<TimeCheck>( () => return new TimeCheck() );
private List<string> list1 = new List<string>();
private readonly object Locker = new object();
public override void DoWork()
{
lock(Locker){
// ... add items to list1
// Write if a) list1 has 500+ items or b) 2 minutes since last write have passed
if( list1.Count >= MAXITEMS || timecheck.Value.IsTimeoutReached )
{
WriteToFile(list1);
list1.Clear(); // assuming _all_ Items are written.
timecheck.Value.Reset();
}
}
}
Attention:
If code is called by multiple threads, you need to make sure it's thread safe. I used lock which will create a bottleneck. You may want to figure out a more sophisticated manner, but this answer concentrates on the condition requirements.
Above snippet assumes, list1 is not accessed elsewhere.
static void Main(string[] args)
{
for (int i = 0; i < int.MaxValue; i++)
{
client client[i] = new client();
}
}
I need to make the loop add an automated variable that gets declared with every loop. The variable would be called client1 then client2 etc. Or is there a better way to loop methods?
Instead of creating n variables for n iterations, why not use a List<clinet> instead like so:
var clients = new List<client>();
for (int i = 0; i < int.MaxValue; i++)
{
clients.Add(new client());
}
Or even simpler:
var clients = Enumerable.Range(0, int.MaxValue).Select(x => new client()).ToList();
Or still simpler:
var clients = Enumerable.Repeat(new client(), int.MaxValue);
Now you can access any client by it´s index, e.g.:
client c = clients[0];
Anyway be aware that you´re creating int.MaxValue number of client-instances. Depending on what client is you´re burning your memory.
NB: Please consider the naming-conventions, e.g. by calling classes like your client-class UpperCase: Client.
If you really need the access to all your variables, #HimBromBeere is right. But if you, for example, have static field in the Client class and only need current variable, you can do something like:
while(true) { var c = new Client(); }
In this case you can check your current state. For example: c.Name; will give you information about the client, which is processed at the current iteration. It will work, if you do all your staff for each client and doesn't need to store info about rest of clients any longer.
Update
My answer is ambiguous. I meant that Client constructor can do something like:
class Client {
static int count = 0;
public string Name { get; set; }
public Client() {
Name = string.Format("client{0}", count++);
}
}
In this case class have static count this tells how many clients did we have. We doesn't use it in our code, but we can understand it while using current client by his name.
I have inherited a WCF web service application that requires to have much better error tracking. What we do is query data from one system (AcuODBC), and send that data to another system (Salesforce). This query will return 10's of thousands of complex objects as a List<T>. We then process this List<T> in batches of 200 records at a time to map the fields to another object type, then send that batch to Salesforce. After this is completed, the next batch starts. Here's a brief example:
int intStart = 0, intEnd = 200;
//done in a loop, snipped for brevity
var leases = from i in trleases.GetAllLeases(branch).Skip(intStart).Take(intEnd)
select new sforceObject.SFDC_Lease() {
LeaseNumber = i.LeaseNumber.ToString(),
AccountNumber = i.LeaseCustomer,
Branch = i.Branch
(...)//about 150 properties
//do stuff with list and increment to next batch
intStart += 200;
However, the problem is if one object has a bad field mapping (Invalid Cast Exception), I would like to print out the object that failed to a log.
Question
Is there any way I can decipher which object of the 200 threw the exception? I could forgo the batch concept that was given to me, but I'd rather avoid that if possible for performance reasons.
This should accomplish what you are looking for with very minor code changes:
int intStart = 0, intEnd = 200, count = 0;
List<SDFC_Lease> leases = new List<SDFC_Lease>();
//done in a loop, snipped for brevity
foreach(var i in trleases.GetAllLeases(branch).Skip(intStart).Take(intEnd)) {
try {
count++;
leases.Add(new sforceObject.SFDC_Lease() {
LeaseNumber = i.LeaseNumber.ToString(),
AccountNumber = i.LeaseCustomer,
Branch = i.Branch
(...)//about 150 properties);
} catch (Exception ex) {
// you now have you culprit either as 'i' or from the index 'count'
}
}
//do stuff with 'leases' and increment to next batch
intStart += 200;
I think that you could use a flag in each set method of the properties of the class SFDC_Lease, and use a static property for this like:
public class SFDC_Lease
{
public static string LastPropertySetted;
public string LeaseNumber
{
get;
set
{
LastPropertySetted = "LeaseNumber";
LeaseNumber = value;
}
}
}
Plz, feel free to improve this design.
It has to be trivial, but I just cannot get through it.
I have to limit amount of tasks (let's say connections, emails sent or clicks in the button) per amount of time. So e.g. I can send 1000 emails per hour.
How can I do that in c#? I don't know and don't care how much time each operation will take. I just want to make sure that for last hour, only 1000 will be executed.
class EventLimiter
{
Queue<DateTime> requestTimes;
int maxRequests;
TimeSpan timeSpan;
public EventLimiter(int maxRequests, TimeSpan timeSpan)
{
this.maxRequests = maxRequests;
this.timeSpan = timeSpan;
requestTimes = new Queue<DateTime>(maxRequests);
}
private void SynchronizeQueue()
{
while ((requestTimes.Count > 0) && (requestTimes.Peek().Add(timeSpan) < DateTime.UtcNow))
requestTimes.Dequeue();
}
public bool CanRequestNow()
{
SynchronizeQueue();
return requestTimes.Count < maxRequests;
}
public void EnqueueRequest()
{
while (!CanRequestNow())
Thread.Sleep(requestTimes.Peek().Add(timeSpan).Subtract(DateTime.UtcNow));
// Was: System.Threading.Thread.Sleep(1000);
requestTimes.Enqueue(DateTime.UtcNow);
}
}
Assuming a rolling hour window:
Maintain a list of when actions were done.
Each time you want to do your action, remove all in the list not within the hour.
If there are fewer than 1000 then do the action and add a record to your list.
Assuming hourly:
Create a proxy method and a variable that is incremented for every action, and reduced to zero on the hour.
Do your action if the counter is < 1000.
The above solution looked fine. Here is my trimmed down version:
public class EmailRateHelper
{
private int _requestsPerInterval;
private Queue<DateTime> _history;
private TimeSpan _interval;
public EmailRateHelper()
: this(30, new TimeSpan(0, 1, 0)) { }
public EmailRateHelper(int requestsPerInterval, TimeSpan interval)
{
_requestsPerInterval = requestsPerInterval;
_history = new Queue<DateTime>();
_interval = interval;
}
public void SleepAsNeeded()
{
DateTime now = DateTime.Now;
_history.Enqueue(now);
if (_history.Count >= _requestsPerInterval)
{
var last = _history.Dequeue();
TimeSpan difference = now - last;
if (difference < _interval)
{
System.Threading.Thread.Sleep(_interval - difference);
}
}
}
}
You can use Rx extensions (How to use the new BufferWithTimeOrCount in Rx that returns IObservable<IObservable<T>> instead of IObservable<IList<T>>), but I would implement the buffering manually by adding an appropriate proxy object.
You may also consider storing {action, time, user} information in a database and get number of actions in a last hour fomr the DB (or similar persisted storager) if you need to handle Application pool restarts / crashes. Otherwise clever user may circumvent your in-memory protection with overloading your server.
You can create a persistent counter for every user. Every time you receive a request (for sending an email) you need to check the value of the counter and the date of the counter creation.
If the count is greater than the limit you refuse the request
If the date is older than an hour you reset the counter and set the new creation date
If the date is correct and the count is under the limit you increase the counter
Only in the last two cases the request is executed.
I have a code like this,In this context HandleDisconnectEventCB will trigger when client has some modified whithout saved data and disconnected(remove network cable) from server,,then it will make 'clientWithLock= 0' and will remove from collection that is shown below code. But now the problem is other connected clients cannot make changes,it showing that 'clientWithLock' has some data not zero,due to that it will show another user is updating data please wait.Is there any badlogic going on here
private static int clientWithLock = 0;
static private void HandleDisconnectEventCB(SPD.SPD_serverLocationType loc,
string server, int clientId,
object passback)
{
// Remove lock if necessary
if (clientWithLock == clientId) clientWithLock = 0;
// Remove client from client list and end replicated display sessions
for (int i = 0; i < clients.Count; i++)
{
SPURTclient sc = (SPURTclient)clients[i];
if (sc.ClientId == clientId)
{
.
.
clients.RemoveAt(i);
break;
Making clientwithlock static is going to cause you all kinds of headaches here if you have multiple disconnects in rapid succession. I'd recommend either making the whole operation stateless, so 'ClientWithLock' is passed as a parameter to the event, and you operate the static function based on all parameters passed. If 'ClientWithLock' is updated twice in fast succession for disconnects, behaviour will be quite strange.
Or, instancing the whole class and operation so the disconnection handler is instanced on a class by class basis if having the whole thing stateless is not an option for you.