I have got problem with contextInfo
[WebMethod]
[SoapHeader("UserInfo", Direction = SoapHeaderDirection.In)]
public void TestContext()
{
var user = ContextInfo.Current.User.LoginName;
}
UserInfo _userInfo;
[System.Xml.Serialization.SoapElement(IsNullable = true)]
public UserInfo UserInfo
{
get { return _userInfo; }
set { _userInfo = value; }
}
When I run my asmx at local everything goes fine, it enter to
public void Init(HttpApplication httpApp).
But when I run my webservice at service it doesn't and I get error at
ContextInfo.Current.User.LoginName;
because Current is null.
I check this by remote debugger.
I have Windows Server 2008 and I am in domain like my server.
public class AuthenticateRequestHttpModule : IHttpModule
{
private HttpApplication mHttpApp;
public void Init(HttpApplication httpApp)
{
this.mHttpApp = httpApp;
mHttpApp.AuthenticateRequest += new EventHandler(OnAuthentication);
}
...
}
ContextInfo:
public class ContextInfo
{
public static void Create(User user)
{
HttpContext.Current.Items.Add(ITEM_KEY, new ContextInfo(user));
}
public static ContextInfo Current
{
get
{
return HttpContext.Current.Items[ITEM_KEY] as ContextInfo;
}
}
private ContextInfo(User user)
{
_user = user;
}
public User User
{
get { return _user; }
}
User _user;
private const string ITEM_KEY = "ContextInfo";
}
Any ideas ?
there was a problem with application pool.
Related
how to send verificationId from SendOtpCodeAsync() to SendCode_Button_Clicked()
Share Project code
IAuth auth;
auth = DependencyService.Get<IAuth>();
private async void SendCode_Button_Clicked(object sender, EventArgs e)
{
bool result = await auth.SendOtpCodeAsync(PhonenumberEntry.Text);
}
android project code
[assembly: Dependency(typeof(AuthDriod))]
namespace TestApp_MiniApps.Droid
{
public class AuthDriod : PhoneAuthProvider.OnVerificationStateChangedCallbacks, IAuth
{
private TaskCompletionSource<bool> _phoneAuthTcs;
public Task<bool> SendOtpCodeAsync(string phonenumber)
{
_phoneAuthTcs = new TaskCompletionSource<bool>();
Java.Lang.Long num = (Java.Lang.Long)60;
PhoneAuthOptions options =
PhoneAuthOptions.NewBuilder(FirebaseAuth.Instance)
.SetPhoneNumber(phonenumber) // Phone number to verify
.SetTimeout(num, TimeUnit.Seconds) // Timeout and unit
.SetActivity(Platform.CurrentActivity) // Activity (for callback binding)
.SetCallbacks(this) // OnVerificationStateChangedCallbacks
.Build();
PhoneAuthProvider.VerifyPhoneNumber(options);
return _phoneAuthTcs.Task;
}
public override void OnVerificationCompleted(PhoneAuthCredential credential)
{
}
public override void OnVerificationFailed(FirebaseException exception)
{
_phoneAuthTcs?.TrySetResult(false);
}
public override void OnCodeSent(string verificationId, PhoneAuthProvider.ForceResendingToken forceResendingToken)
{
base.OnCodeSent(verificationId, forceResendingToken);
_phoneAuthTcs?.TrySetResult(true);
}
}//end of class
}
share project interface
namespace TestApp_MiniApps.Views.Xamarin.FireBase
{
public interface IAuth
{
Task<bool> SendOtpCodeAsync(string phonenumber);
}//end of class
}
To summarise what Leo had put in the comments you can check what is returned from your method call.
Change from bool to your own class. For the purpose of this answer I will call it OtpResult.
// The new class definition:
public class OtpResult
{
public bool Success { get; set; }
// Define whatever you like here
public string StringValue { get; set; }
}
public interface IAuth
{
Task<OtpResult> SendOtpCodeAsync(string phonenumber);
}
I have this method:
public static async Task OpenPageAsync(string route)
{
await Shell.Current.GoToAsync(route, true);
}
If the method is called more than once in 5 seconds I would like the second call to be ignored. Has anyone come across a way to deal with this need?
Note that if it helps I do have access to create properities at the App level like this etc.
public partial class App : Application
{
public static int LastTapTime;
public static int TapTime;
In our project, we have created a 'MaxFrequencyUpdater' for exactly that cause.
Only difference: if within 5 seconds a new call comes in, it is delayed and executed after the 5 seconds interval.
namespace Utils
{
public class MaxFrequencyUpdater
{
private readonly WinformsExceptionHandler _exceptionHandler;
private readonly string _name;
private readonly int _millis;
private MethodInvoker _currentMethod;
private DateTime _lastExecuted = DateTime.MinValue;
private readonly object _updaterLockObject = new object();
public MaxFrequencyUpdater(string name, int maxFrequencyInMillis, WinformsExceptionHandler exceptionHandler)
{
_name = name;
_exceptionHandler = exceptionHandler;
_millis = maxFrequencyInMillis;
}
public void Update(MethodInvoker method)
{
lock (_updaterLockObject)
{
_currentMethod = method;
}
Task.Run(HandleWork);
}
private void HandleWork()
{
lock (_updaterLockObject)
{
// No longer bother, someone else handled it already
if (_currentMethod == null) return;
var now = DateTime.Now;
var delay = (int)(_millis - now.Subtract(_lastExecuted).TotalMilliseconds);
// Post-pone if too soon
if (delay > 0)
{
Task.Delay(delay).ContinueWith(HandleWork);
}
else
{
try
{
_currentMethod.Invoke();
}
catch (Exception e)
{
_exceptionHandler.HandleException(e);
}
_lastExecuted = now;
_currentMethod = null;
}
}
}
}
}
usage:
_maxFrequencyUpdater.Update(() =>
{
doSomething();
});
I have implemented this Windows Service which sends emails using SendAsync method, every 30 seconds in batches of 20. I'm using EF6 and SQL Server 2016. Here is some parts of the codes
EmailRepository.cs
public class EmailRepository : IEmailRepository
{
private BBEntities db = null;
public EmailRepository(BBEntities db)
{
this.db = db;
}
public IEnumerable<tb_Email> SelectAll(int batchAge, int batchSize)
{
DateTime tDate = DateTime.Now.AddMinutes(batchAge);
return db.tb_Email.Where(x => x.ReadyToSend.Equals(true) & x.DateSent.Equals(null) & x.DateCreated >= tDate).OrderBy(x => x.DateCreated).Take(batchSize);
}
public tb_Email SelectByID(Guid id)
{
return db.tb_Email.Find(id);
}
public void Update(tb_Email obj)
{
db.Entry(obj).State = EntityState.Modified;
}
#region IDisposable Support
private bool disposedValue = false;
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
db.Dispose();
}
disposedValue = true;
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
#endregion
}
UnitOfWork.cs
public class UnitOfWork : IUnitOfWork
{
private readonly BBEntities ctx = new BBEntities();
private IEmailRepository emailRepository;
public IEmailRepository EmailRepository
{
get
{
if (this.emailRepository == null)
{
this.emailRepository = new EmailRepository(ctx);
}
return emailRepository;
}
}
public void Dispose()
{
this.ctx.Dispose();
}
public void Commit()
{
this.ctx.SaveChanges();
}
}
EmailService.cs
public class EmailService : IEmailService
{
private IUnitOfWork unitOfWork;
public EmailService()
{
unitOfWork = new UnitOfWork();
}
public List<tb_Email> SelectAll(int batchAge, int batchSize)
{
return unitOfWork.EmailRepository.SelectAll(batchAge, batchSize).ToList();
}
public tb_Email SelectByID(Guid id)
{
return unitOfWork.EmailRepository.SelectByID(id);
}
public void Update(tb_Email obj)
{
using (unitOfWork = new UnitOfWork())
{
unitOfWork.EmailRepository.Update(obj);
unitOfWork.Commit();
}
}
}
SMTPService.cs
public class SMTPService : ISMTPService
{
SmtpClient client;
MailMessage newMessage;
EmailService emailService;
IEventLoggerService MailCheckerLog;
public SMTPService()
{
emailService = new EmailService();
MailCheckerLog = new EventLoggerService();
}
public void SendEmail(tb_Email email)
{
try
{// rest of the code .....
newMessage = new MailMessage();
newMessage.Headers.Add("X-Email_Id", email.Id.ToString());
client.SendCompleted += (sender, e) => SendCompletedCallback(sender, e);
tb_Email userState = email;
//
// if I put the update database logic here, it works fine
//
client.SendAsync(newMessage, userState);
}
catch (Exception e)
{
MailCheckerLog.log("Error in SendComplete event handler - Exception: " + e.Message.ToString() + " -- InnerException: " + e.InnerException.Message, EventLogEntryType.Error);
client.Dispose();
newMessage.Dispose();
throw;
}
}
void SendCompletedCallback(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
{
tb_Email email = (tb_Email)e.UserState;
Console.WriteLine("----------------------------------" + emailID.Id);
email.ReadyToSend = false;
emailService.Update(email);
client.Dispose();
newMessage.Dispose();
}
}
The problem:
So to send and process emails I run SendEmail method in a simple loop with a list of tb_Email objects, once each email is sent I have to update the database.
To do that, I use
email.ReadyToSend = false;
emailService.Update(email);
in my SendCompleted event, as I'm using SendAsync the system goes ahead and process many emails however the SendCompleted event might fire a bit later for each email.
To make sure it is using a unique and single dbContext I am using a using statement on my UoW instance for the update method. This works fine if I put my update logic in SendEmail method directly (which doesn't make any sense as I need to know if the email was sent successfully or not), however If I put it in the event after a few successful updates, it just throw
System.Data.Entity.Core.EntityException: 'The underlying provider failed on Open.'
I don't understand how is it possible when I'm actually creating a new context for each operation.
Sorry I have to answer it myself, the problem was that the UoW variable was still being used by other threads, so the solution is to declare a new variable for the using statement inside the update method, like below
public class EmailService : IEmailService
{
private IUnitOfWork unitOfWork;
public EmailService()
{
unitOfWork = new UnitOfWork();
}
public List<tb_Email> SelectAll(int batchAge, int batchSize)
{
return unitOfWork.EmailRepository.SelectAll(batchAge, batchSize).ToList();
}
public tb_Email SelectByID(Guid id)
{
return unitOfWork.EmailRepository.SelectByID(id);
}
public void Update(tb_Email obj)
{
IUnitOfWork unitOfWorkUpdate;
using (unitOfWorkUpdate = new UnitOfWork())
{
unitOfWorkUpdate.EmailRepository.Update(obj);
unitOfWorkUpdate.Commit();
}
}
}
I'm new in Microsoft Message Queue in Windows Server, I need to push, if the EmployeeID is NULL.
The Employee Model Class is
public class Employee
{
public string EmployeeID { get; set; }
public string EmployeeName { get; set; }
}
public void ValidationProcess(Employee emp)
{
if((emp != null) || (emp.EmployeeID == null))
{
// Push into Validation Exception Queue using MSMQ
}
}
Once the Data pushed into that Validation Exception Queue, it should be processed by separate process. Every 1hr the process need to initiate and it should call the following method
public void ValidationExceptionProcess(object obj)
{
// Some Inner Process
// Log the Error
}
Kindly guide me how to create and process it.
First Step:
Install MSMQs as a windows feature on the server/pc
Then:
- Create the queue if it does not exist
- Push the message in the queue asynchronously
Useful guide
Code example for pushing and retrieving messages from msmq:
public class ExceptionMSMQ
{
private static readonly string description = "Example description";
private static readonly string path = #".\Private$\myqueue";
private static MessageQueue exceptionQueue;
public static MessageQueue ExceptionQueue
{
get
{
if (exceptionQueue == null)
{
try
{
if (MessageQueue.Exists(path))
{
exceptionQueue = new MessageQueue(path);
exceptionQueue.Label = description;
}
else
{
MessageQueue.Create(path);
exceptionQueue = new MessageQueue(path);
exceptionQueue.Label = description;
}
}
catch
{
throw;
}
finally
{
exceptionQueue.Dispose();
}
}
return exceptionQueue;
}
}
public static void PushMessage(string message)
{
ExceptionQueue.Send(message);
}
private static List<string> RetrieveMessages()
{
List<string> messages = new List<string>();
using (ExceptionQueue)
{
System.Messaging.Message[] queueMessages = ExceptionQueue.GetAllMessages();
foreach (System.Messaging.Message message in queueMessages)
{
message.Formatter = new XmlMessageFormatter(
new String[] { "System.String, mscorlib" });
string msg = message.Body.ToString();
messages.Add(msg);
}
}
return messages;
}
public static void Main(string[] args)
{
ExceptionMSMQ.PushMessage("my exception string");
}
}
An other widely used way to do that would also be to use out of the box loggers which already contains this functionality like Enterprise Library or NLog which provide easy interfaces to do that.
For retrieving messages I would recommend a separate windows service which would periodically read messages and process them. An good example on how to do that is given here: Windows service with timer
Update: Windows Service Example:
MSMQConsumerService.cs
public partial class MSMQConsumerService : ServiceBase
{
private System.Timers.Timer timer;
public MSMQConsumerService()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
this.timer = new System.Timers.Timer(30000D); // 30000 milliseconds = 30 seconds
this.timer.AutoReset = true;
this.timer.Elapsed += new System.Timers.ElapsedEventHandler(this.ProcessQueueMessages);
this.timer.Start();
}
protected override void OnStop()
{
this.timer.Stop();
this.timer = null;
}
private void ProcessQueueMessages(object sender, System.Timers.ElapsedEventArgs e)
{
MessageProcessor.StartProcessing();
}
}
and the MessageProcessor.cs
public class MessageProcessor
{
public static void StartProcessing()
{
List<string> messages = ExceptionMSMQ.RetrieveMessages();
foreach(string message in messages)
{
//write message in database
}
}
}
Below you can see a simplified version of my SignalR self hosted hub on a windows service:
public static class SubscriptionHandler
{
public static int PriceFeedMembersCount = 0;
}
public class PriceHub : Hub
{
public Task SubscribeToPriceFeed()
{
IHubContext context = GlobalHost.ConnectionManager.GetHubContext<PriceHub>();
if (SubscriptionHandler.PriceFeedMembersCount == 0)
{
context.Clients.All.updatePriceSubscriptionStatus(true);
}
SubscriptionHandler.PriceFeedMembersCount++;
return context.Groups.Add(Context.ConnectionId, "PriceFeed");
}
public Task UnsubscribeFromPriceFeed()
{
IHubContext context = GlobalHost.ConnectionManager.GetHubContext<PriceHub>();
SubscriptionHandler.PriceFeedMembersCount--;
if (SubscriptionHandler.PriceFeedMembersCount == 0)
{
context.Clients.All.updatePriceSubscriptionStatus(false);
}
return context.Groups.Remove(Context.ConnectionId, "PriceFeed");
}
public void NotifySubscribers(Price price)
{
IHubContext context = GlobalHost.ConnectionManager.GetHubContext<PriceHub>();
context.Clients.Group("PriceFeed").updatePrice(price);
}
}
And I have two types of clients for that hub: One of them is web applications and the other one is windows services. Here you can see a demo implementation for my windows service as a signalr client:
public partial class WinSer45 : ServiceBase
{
private HubConnection hubConnection;
private IHubProxy priceProxy;
private Timer timer = new Timer();
private bool hasSubscribers = false;
public WinSer45()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
timer.Interval = 1000; // saniyede bir
timer.Elapsed += timer_Elapsed;
timer.Enabled = true;
hubConnection = new HubConnection("http://localhost:8080/signalr", useDefaultUrl: false);
priceProxy = hubConnection.CreateHubProxy("PriceHub");
hubConnection.Start().Wait();
priceProxy.On<bool>("UpdatePriceSubscriptionStatus", hasSubscribers =>
{
this.hasSubscribers = hasSubscribers;
});
}
void timer_Elapsed(object sender, ElapsedEventArgs e)
{
if (hasSubscribers)
{
TestPrice testPrice = new TestPrice() { Id = 1, Buy = 1.2345, Sell = 9.8765, Symbol = "EURUSD" };
priceProxy.Invoke("NotifySubscribers", testPrice).Wait();
}
}
protected override void OnStop()
{
}
}
As you see I use the hasSubscribers flag to minimize the messages between hub and clients. And hasSubscribers flag is changed by SubscribeToPriceFeed and UnsubscribeFromPriceFeed methods.
If you look carefully you see the line below in SubscribeToPriceFeed:
context.Clients.All.updatePriceSubscriptionStatus(true);
I don't want to send the message to all clients but my client windows service. How can I store the connection Id of a specific client in my hub? If I can do that, I know I can send message to a specific connectionId as in the line below:
context.Clients.Client(connectionId).updatePriceSubscriptionStatus(true);
Thanks in advance,
pass source during connection
like this
hubConnection = new HubConnection("http://localhost:8080/signalr","source=windows",useDefaultUrl: false);
HUB
public override Task OnConnected()
{
var source= Context.QueryString['source'];
return base.OnConnected();
}
create a class which will hold the user with source
public class user {
public string ConnectionID {set;get;}
public string Source {set;get;}
}
declare a list in the hub
List<user> userList=new List<user>();
Then push the user during OnConnected
public override Task OnConnected()
{
var us=new user();
us.Source = Context.QueryString['source'];
us.ConnectionID=Context.ConnectionId;
userList.Add(us);
return base.OnConnected();
}
and during broadcast just filter it by source
var windowsUser=userList.Where(o=>o.Source == "windows").ToList(); // you'll get the windows user list