"'Object reference not set to an instance of an object" When I Started App - asp.net-core

I have got some Classes implements IHostedService.
EmailSendService:
public class EMailSendService : IHostedService, IDisposable
{
private Timer _timer;
private IMailAccountService _mailAccountService;
private IMailTaskDAL _mailTaskDal;
private LoggerServiceBase _loggerServiceBase;
public EMailSendService(IMailAccountService mailAccountService, IMailTaskDAL mailTaskDal)
{
_mailAccountService = mailAccountService;
_mailTaskDal = mailTaskDal;
_loggerServiceBase = (LoggerServiceBase)Activator.CreateInstance(typeof(DatabaseLogger));
}
private void SendMail(object state)
{
var isAnyMailSended = false;
var logDetail = new LogDetail
{
UserID = "",
UserAgent = "",
IP = "System",
MethodName = "SENDMAILTASK",
StackTrace = "",
TraceIdentifier = ""
};
try
{
var now = DateTime.Now;
var mailTasks = _mailTaskDal.GetList(op => !op.IsSended && op.NextSendDate < now && op.TryCount < 10);
isAnyMailSended = mailTasks.Count > 0;
foreach (var mailTask in mailTasks)
{
var toList = mailTask.ToList.Split(',');
var sendResult = _mailAccountService.SendMail(toList, mailTask.Subject, mailTask.Body);
mailTask.Result = sendResult.Messages[0].Description;
if (sendResult.Success)
{
mailTask.IsSended = true;
mailTask.SendDate = DateTime.Now;
}
else
{
mailTask.NextSendDate = DateTime.Now.AddMinutes(5);
mailTask.TryCount++;
}
_mailTaskDal.Update(mailTask);
}
}
catch (Exception e)
{
logDetail.ExceptionMessage = e.Message;
logDetail.StackTrace = e.StackTrace;
}
finally
{
if (isAnyMailSended)
_loggerServiceBase.Info(logDetail);
}
}
public System.Threading.Tasks.Task StartAsync(CancellationToken cancellationToken)
{
_timer = new Timer(SendMail, null, TimeSpan.Zero, TimeSpan.FromSeconds(30));
return System.Threading.Tasks.Task.CompletedTask;
}
public System.Threading.Tasks.Task StopAsync(CancellationToken cancellationToken)
{
_timer?.Change(Timeout.Infinite, 0);
return System.Threading.Tasks.Task.CompletedTask;
}
public void Dispose()
{
_timer?.Dispose();
}
}
CreateActivityTask:
public class CreateActivityTask : IHostedService, IDisposable
{
private Timer _timer;
private LoggerServiceBase _loggerServiceBase;
public CreateActivityTask()
{
_loggerServiceBase = (LoggerServiceBase)Activator.CreateInstance(typeof(DatabaseLogger));
}
private void CreateActivity(object state)
{
var logDetail = new LogDetail
{
UserID = "",
UserAgent = "",
IP = "System",
MethodName = "CreateActivityTask",
StackTrace = "",
TraceIdentifier = ""
};
try
{
//create activity
}
catch (Exception e)
{
logDetail.ExceptionMessage = e.Message;
logDetail.StackTrace = e.StackTrace;
}
finally
{
_loggerServiceBase?.Info(logDetail);
}
}
public System.Threading.Tasks.Task StartAsync(CancellationToken cancellationToken)
{
_timer = new Timer(CreateActivity, null, TimeSpan.Zero, TimeSpan.FromSeconds(60));
return System.Threading.Tasks.Task.CompletedTask;
}
public System.Threading.Tasks.Task StopAsync(CancellationToken cancellationToken)
{
_timer?.Change(Timeout.Infinite, 0);
return System.Threading.Tasks.Task.CompletedTask;
}
public void Dispose()
{
_timer?.Dispose();
}
}
I Use two extension function to add this classes in startup.cs -> ConfigureServices:
services.AddHostedService<EMailSendService>();
services.AddHostedService<CreateActivityTask>();
But if i use like that, program does not run. When i start it, this code throws an error:
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run(); // This is where throws error
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseServiceProviderFactory(new AutofacServiceProviderFactory())
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
Error Detail:
System.NullReferenceException
HResult=0x80004003
Message=Object reference not set to an instance of an object.
Source=Microsoft.Extensions.Hosting
StackTrace:
at Microsoft.Extensions.Hosting.Internal.Host.<StartAsync>d__9.MoveNext()
If i comment
services.AddHostedService();
Still i get the error. But if i comment all "CreateActivityTask" class and "services.AddHostedService();", then i can run the app.
EmailTaskService can run properly. But if i left "CreateActivityTask" alone (I mean, i commented all "EmailTaskService class etc..), program gets error again.
I can't see any error on CreateActivity class, so i can't find where is the mistake. Could you help me please?

Related

How can I create filter for UnauthorizedAccessException

I want to create filter for UnauthorizedAccessException I ddon't know why it is not work in my main filter
at first I try this in my ApiExceptionFilter : ExceptionFilterAttribute but doesn't worked here
private void HandleUnauthorizedAccessException(ExceptionContext context)
{
var exception = context.Exception as UnauthorizedAccessException;
var details = new ProblemDetails
{
Status = StatusCodes.Status401Unauthorized,
Title = "nauthorized exception",
Detail = exception.Message
};
context.Result = new ObjectResult(details)
{
StatusCode = StatusCodes.Status401Unauthorized
};
context.ExceptionHandled = true;
}
every other my exceptions work here instead of this
after that I try get that here but not successful again :
public class HttpResponseExceptionFilter : IActionFilter, IOrderedFilter
{
public int Order { get; set; } = int.MaxValue - 10;
public void OnActionExecuting(ActionExecutingContext context) { }
public void OnActionExecuted(ActionExecutedContext context)
{
if (context.Exception is HttpResponseException exception)
{
context.Result = new ObjectResult(exception.Value)
{
StatusCode = exception.Status,
};
context.ExceptionHandled = true;
}
}
}
I dont know why only this exception not worked after request send to api :(

ASP.NET Core 2.2 Can't invoke Razor Page from custom middleware

I am trying to create custom exception handling middlware. similar to -> app.UseExceptionHandler("/Error"). I will log the error in middleware and then i want invoke Error page.
The problem is, when i do redirect then IExceptionHandlerFeature object from context.Features.Get() is NULL.
Seems that context exceptions are cleared when Razorpage is executed. In the original middleware it somehow works.
public class ExceptionMiddleware
{
private readonly RequestDelegate _next;
private readonly ILoggerFactory _loggerFactory;
public ExceptionMiddleware(RequestDelegate next, ILoggerFactory loggerFactory)
{
_loggerFactory = loggerFactory;
_next = next;
}
public async Task InvokeAsync(HttpContext httpContext)
{
try
{
await _next(httpContext);
}
catch (Exception ex)
{
var logger = _loggerFactory.CreateLogger("Serilog Global exception logger");
logger.LogError($"Something went wrong: {ex}");
await HandleExceptionAsync(httpContext, ex);
}
}
private async Task HandleExceptionAsync(HttpContext context, Exception exception)
{
context.Response.ContentType = "application/json";
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
context.Response.Redirect("/ErrorHandling/Error");
await Task.CompletedTask;
}
}
Here is my Razor Error Page model
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public class ErrorModel : PageModel
{
private ILogger<ErrorModel> _logger;
public string RequestId { get; set; }
public string ExceptionPath { get; set; }
public string ExceptionMessage { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public ErrorModel(ILogger<ErrorModel> logger)
{
_logger = logger;
}
public void OnGet(string executionPath)
{
var httpCtx = HttpContext;
var exceptionDetails = httpCtx.Features.Get<IExceptionHandlerPathFeature>();
if (exceptionDetails != null)
{
_logger.LogError(httpCtx.Response.StatusCode, exceptionDetails.Error, exceptionDetails.Error.Message);
//Add data for view
ExceptionPath = exceptionDetails.Path;
ExceptionMessage = "An unexpected fault happened. Try again later.";
}
RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
}
}
After redirection httpCtx.Features.Get() should return IExceptionHandlerPathFeature object, but it returns NULL
From the source code of ExceptionHandlerMiddleware and ExceptionHandlerExtensions, you need to use rewrite instead of redirect.
Below is simplified code of custom ExceptionMiddleware
public class ExceptionMiddleware
{
private readonly RequestDelegate _next;
private readonly ILoggerFactory _loggerFactory;
public ExceptionMiddleware(
RequestDelegate next,
ILoggerFactory loggerFactory
)
{
_next = next;
_loggerFactory = loggerFactory;
}
public async Task InvokeAsync(HttpContext httpContext)
{
try
{
await _next(httpContext);
}
catch (Exception ex)
{
var logger = _loggerFactory.CreateLogger("Serilog Global exception logger");
logger.LogError($"Something went wrong: {ex}");
await HandleExceptionAsync(httpContext, ex);
}
}
private async Task HandleExceptionAsync(HttpContext context, Exception ex)
{
PathString originalPath = context.Request.Path;
context.Request.Path = "/Error";
try
{
var exceptionHandlerFeature = new ExceptionHandlerFeature()
{
Error = ex,
Path = originalPath.Value,
};
context.Features.Set<IExceptionHandlerFeature>(exceptionHandlerFeature);
context.Features.Set<IExceptionHandlerPathFeature>(exceptionHandlerFeature);
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
await _next(context);
return;
}
catch (Exception ex2)
{
}
finally
{
context.Request.Path = originalPath;
}
}
}

Pusher with Service application on Android dose not bind events

I had a problem with Pusher with Service application on Android.
When I using pusher on Application or Activity then It's working.
But I move it to Service and register with application in manifress like:
<service android:name=".services.PusherServices"/>
It's not working.
When i startService Pusher connected success with authorization, but It's not bind events when I call method for register Channel.
PusherServices.java
package vn.hemlock.winkle.pancake.services;
import android.app.Activity;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import com.pusher.client.Pusher;
import com.pusher.client.PusherOptions;
import com.pusher.client.channel.PrivateChannel;
import com.pusher.client.channel.PrivateChannelEventListener;
import com.pusher.client.connection.ConnectionEventListener;
import com.pusher.client.connection.ConnectionState;
import com.pusher.client.connection.ConnectionStateChange;
import com.pusher.client.util.HttpAuthorizer;
import net.windjs.android.utils.Encrypt;
import net.windjs.android.utils.Log;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.HashMap;
import vn.hemlock.winkle.pancake.abstracts.ChatEvents;
import vn.hemlock.winkle.pancake.contracts.ServicesURI;
import vn.hemlock.winkle.pancake.ui.Conversation;
import vn.hemlock.winkle.pancake.ui.Message;
import vn.hemlock.winkle.pancake.ui.Page;
/**
* Created by me866chuan on 5/4/15.
*/
public class PusherServices extends Service {
private String LOG_TAG = "Pusher Services";
private boolean pusherOn = false;
public final String PUSHER_KEY = "...";
private String userToken = "";
private String userID = "";
private final IBinder mBinder = new LocalBinder();
public boolean isPusherOn() {
return pusherOn;
}
public void setPusherOn(boolean pusherOn) {
this.pusherOn = pusherOn;
}
public String getUserToken() {
return userToken;
}
public void setUserToken(String userToken) {
this.userToken = userToken;
}
public String getUserID() {
return userID;
}
public void setUserID(String userID) {
this.userID = userID;
}
#Override
public IBinder onBind(Intent intent) {
setUserID(intent.getStringExtra("userId"));
setUserToken(intent.getStringExtra("userToken"));
startPusher();
startService(intent);
return mBinder;
}
#Override
public boolean onUnbind(Intent intent) {
Log.e(LOG_TAG, "OFF");
stopService(intent);
return true;
}
#Override
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
pusher.disconnect();
}
private Pusher pusher;
public void startPusher() {
HashMap<String, String> hash = new HashMap<>();
Log.e(LOG_TAG, "Token: "+getUserToken());
hash.put("authorization", getUserToken());
HttpAuthorizer authorizer = new HttpAuthorizer(ServicesURI.PUSHER_AUTHORIZER);
authorizer.setHeaders(hash);
PusherOptions options = new PusherOptions().setAuthorizer(authorizer);
pusher = new Pusher(PUSHER_KEY, options);
pusher.connect(new ConnectionEventListener() {
#Override
public void onConnectionStateChange(ConnectionStateChange change) {
Log.e(LOG_TAG, "State changed to " + change.getCurrentState() +
" from " + change.getPreviousState());
if(change.getCurrentState().toString().toUpperCase().equals("CONNECTED") || change.getCurrentState().toString().toUpperCase().equals("CONNECTING")){
setPusherOn(true);
}
else setPusherOn(false);
}
#Override
public void onError(String message, String code, Exception e) {
Log.e(LOG_TAG, "There was a problem connecting: " + message);
}
}, ConnectionState.ALL);
}
PrivateChannel userChannel;
public void userListenChanel(final Activity activity) {
if (pusher == null) return;
userChannel = pusher.subscribePrivate("private-" + Encrypt.stringMD5(getUserID()));
userChannel.bind("fetch_accounts", new PrivateChannelEventListener() {
#Override
public void onEvent(String channel, String event, final String data) {
Log.e(LOG_TAG, "Received event with data: " + data);
if (activity != null) activity.runOnUiThread(new Runnable() {
#Override
public void run() {
try {
ChatEvents.getInstance().onNewPage(new Page((new JSONObject(data)).getJSONObject("page")));
} catch (JSONException e) {
e.printStackTrace();
}
}
});
}
#Override
public void onAuthenticationFailure(String s, Exception e) {
Log.e(LOG_TAG, "USER FETCH FAIL: " + s);
}
#Override
public void onSubscriptionSucceeded(String s) {
Log.e(LOG_TAG, "USER FETCH SUCCESS: " + s);
}
});
}
PrivateChannel pageChannel;
private String idPageChannelListen;
public void pageListenChanel(final Activity activity, String pageId) {
if (pusher == null) return;
idPageChannelListen = pageId;
Log.e(LOG_TAG, "Channel page: "+"private-" + Encrypt.stringMD5(pageId));
pageChannel = pusher.subscribePrivate("private-" + Encrypt.stringMD5(pageId));
pageChannel.bind("realtime_updates", new PrivateChannelEventListener() {
#Override
public void onEvent(String channel, String event, final String data) {
Log.e(LOG_TAG, "Real time update with data: " + data);
JSONObject jsonObject = null;
try {
jsonObject = new JSONObject(data);
} catch (JSONException e) {
e.printStackTrace();
}
final JSONObject finalJsonObject = jsonObject;
if(activity != null) activity.runOnUiThread(new Runnable() {
#Override
public void run() {
if (finalJsonObject == null) return;
try {
if (finalJsonObject.has("message")) ChatEvents.getInstance().onNewMessage(new Message(finalJsonObject.getJSONObject("message")));
else if (finalJsonObject.has("conversation")) ChatEvents.getInstance().onNewConversation(new Conversation(finalJsonObject.getJSONObject("conversation")));
} catch (JSONException e) {
e.printStackTrace();
}
}
});
}
#Override
public void onAuthenticationFailure(String s, Exception e) {
Log.e(LOG_TAG, "Real time update failed: " + s);
}
#Override
public void onSubscriptionSucceeded(String s) {
Log.e(LOG_TAG, "Real time update successed: " + s);
}
});
pageChannel.bind("fetch_conversations", new PrivateChannelEventListener() {
#Override
public void onEvent(String channel, String event, final String data) {
Log.e(LOG_TAG, "Received event with data: " + data);
if(activity != null) activity.runOnUiThread(new Runnable() {
#Override
public void run() {
try {
ChatEvents.getInstance().onNewConversation(new Conversation((new JSONObject(data)).getJSONObject("conversation")));
} catch (JSONException e) {
e.printStackTrace();
}
}
});
}
#Override
public void onAuthenticationFailure(String s, Exception e) {
}
#Override
public void onSubscriptionSucceeded(String s) {
}
});
pageChannel.bind("fetch_comments", new PrivateChannelEventListener() {
#Override
public void onEvent(String channel, String event, String data) {
Log.e(LOG_TAG, "Received event with data: " + data);
}
#Override
public void onAuthenticationFailure(String s, Exception e) {
}
#Override
public void onSubscriptionSucceeded(String s) {
}
});
}
public void removeLisnterPage(String pageId) {
if (pusher != null) pusher.unsubscribe("private-" + Encrypt.stringMD5(pageId));
idPageChannelListen = "";
}
public void reconnectPusher() {
if (pusher != null) {
pusher.disconnect();
pusher.connect();
}
}
public void disconnectPusher() {
if (pusher != null) pusher.disconnect();
}
public String getIdPageChannelListen() {
return idPageChannelListen;
}
public class LocalBinder extends Binder {
public PusherServices getService() {
// Return this instance of LocalService so clients can call public methods
return PusherServices.this;
}
}
}

How to use webclient and DownloadStringCompleted windows phone 8

I have class GetInfo (get object from server), Page1.xaml, Page2.xaml. I want tranmission object value from Page1 to Page2
This is my code
Class GetInfo
Class GetInfo{
Info use_info; //(Info is class)
public GetInfo(Info user_info)
{
this.user_info = user_info;
}
public void UseWebClient()
{
var client = new WebClient();
client.DownloadStringCompleted += (sender, e) =>
{
if (!string.IsNullOrEmpty(e.Result))
getInfo(e.Result);
};
client.DownloadStringAsync(new Uri("http://example.com/user_info.php?id=1"));
}
void getInfo()
{
I will Parse JSon string get from server become Info object...
}
}
Class Page1.cs//
Info user_info;
GetInfo userInfo;
public Page1()//constructor
{
userInfo = new GetInfo(user_info);
}
private void LayoutRoot_Loaded(object sender, RoutedEventArgs e)
{
userInfo.UseWebClient();
//THIS IS PROBLEM
if(user_info.name != null) //name is public properties;
{
PhoneApplicationService.Current.State["user_info"] = user_info;
NavigationService.Navigate(new Uri("/Page2.xaml", UriKind.Relative));
}
else
{
MessageBox.Show("Check Connect!", "Warning", MessageBoxButton.OK)
if(result == MessageBoxResult.OK)
Application.Current.Terminate();
}
}
I know DownloadStringCompleted call when event LayoutRoot_Loaded() finish. Problem is I can't move to Page2 if LayoutRoot_Loaded() not finish.
I need solution to solve the problem
Thanks!

Can Client of a WCF Duplex Service(TCP binding) send and recive at the same time?

My code at the moment looks like this:
Server side:
#region IClientCallback interface
interface IClientCallback
{
[OperationContract(IsOneWay = true)]
void ReceiveWcfElement(WcfElement wcfElement);
}
#endregion
#region IService interface
[ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(IClientCallback))]
interface IService
{
[OperationContract(IsOneWay = true, IsInitiating = false, IsTerminating = false)]
void ReadyToReceive(string userName, int source, string ostatniTypWiadomosci);
[OperationContract(IsOneWay = false, IsInitiating = false, IsTerminating = false)]
bool SendWcfElement(WcfElement wcfElement);
[OperationContract(IsOneWay = false, IsInitiating = true, IsTerminating = false)]
List<int> Login(Client name, string password, bool isAuto, bool isSuperMode);
}
#endregion
#region Public enums/event args
public delegate void WcfElementsReceivedFromClientEventHandler(object sender, WcfElementsReceivedFromClientEventArgs e);
public class WcfElementsReceivedFromClientEventArgs : EventArgs
{
public string UserName;
}
public class ServiceEventArgs : EventArgs
{
public WcfElement WcfElement;
public Client Person;
}
#endregion
#region Service
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class Service : IService
{
#region Instance fields
//thread sync lock object
private static readonly Object SyncObj = new Object();
//callback interface for clients
IClientCallback _callback;
//delegate used for BroadcastEvent
public delegate void ChatEventHandler(object sender, ServiceEventArgs e);
public static event ChatEventHandler ChatEvent;
private ChatEventHandler _myEventHandler;
//holds a list of clients, and a delegate to allow the BroadcastEvent to work
//out which chatter delegate to invoke
static readonly Dictionary<Client, ChatEventHandler> Clients = new Dictionary<Client, ChatEventHandler>();
//current person
private Client _client;
#endregion
#region Helpers
private bool CheckIfPersonExists(string name)
{
return Clients.Keys.Any(p => p.UserName.Equals(name, StringComparison.OrdinalIgnoreCase));
}
private ChatEventHandler getPersonHandler(string name)
{
foreach (var c in Clients.Keys.Where(c => c.UserName.Equals(name, StringComparison.OrdinalIgnoreCase)))
{
ChatEventHandler chatTo;
Clients.TryGetValue(c, out chatTo);
return chatTo;
}
return null;
}
private Client GetPerson(string name)
{
return Clients.Keys.FirstOrDefault(c => c.UserName.Equals(name, StringComparison.OrdinalIgnoreCase));
}
#endregion
#region IService implementation
public List<int> Login(Client client, string password, bool isAuto, bool isSuperMode)
{
if (client.ElementsVersions == null)
{
client.ElementsVersions = new WcfElement(WcfElement.RodzajWiadomosci.VersionControl, client.UserName);
}
//create a new ChatEventHandler delegate, pointing to the MyEventHandler() method
_myEventHandler = MyEventHandler;
lock (SyncObj)
{
if (!CheckIfPersonExists(client.UserName))
{
_client = client;
Clients.Add(client, _myEventHandler);
}
else
{
_client = client;
foreach (var c in Clients.Keys.Where(c => c.UserName.Equals(client.UserName)))
{
ChatEvent -= Clients[c];
Clients.Remove(c);
break;
}
Clients[client] = _myEventHandler;
}
_client.LockObj = new object();
}
_callback = OperationContext.Current.GetCallbackChannel<IClientCallback>();
ChatEvent += _myEventHandler;
var rValue = isAuto ? bazaDanych.Login(client.UserName, isSuperMode) : bazaDanych.Login(client.UserName, password);
return rValue;
}
public void PerformDataSync(Client c)
{
WcfElement wcfDelete = null;
WcfElement wcfUpdate = null;
//...
//this method prepares elements for client
//when done it adds them to clients queue (List<WcfElement)
try
{
var counter = 0;
if (wcfDelete != null)
{
foreach (var wcf in WcfElement.SplitWcfElement(wcfDelete, false))//split message into small ones
{
c.AddElementToQueue(wcf, counter++);
}
}
if (wcfUpdate != null)
{
foreach (var wcf in WcfElement.SplitWcfElement(wcfUpdate, true))
{
c.AddElementToQueue(wcf, counter++);
}
}
SendMessageToGui(string.Format("Wstępna synchronizacja użytkownika {0} zakończona.", c.UserName));
c.IsSynchronized = true;
}
catch (Exception e)
{
}
}
private void SendMessageToClient(object sender, EventArgs e)
{
var c = (Client) sender;
if (c.IsReceiving || c.IsSending)
{
return;
}
c.IsReceiving = true;
var wcfElement = c.GetFirstElementFromQueue();
if (wcfElement == null)
{
c.IsReceiving = false;
return;
}
Clients[c].Invoke(this, new ServiceEventArgs { Person = c, WcfElement = wcfElement });
}
public void ReadyToReceive(string userName)
{
var c = GetPerson(userName);
c.IsSending = false;
c.IsReceiving = false;
if (c.IsSynchronized)
{
SendMessageToClient(c, null);
}
else
{
PerformDataSync(c);
}
}
public bool SendWcfElement(WcfElement wcfElement)
{
var cl = GetPerson(wcfElement.UserName);
cl.IsSending = true;
if (wcfElement.WcfElementVersion != bazaDanych.WcfElementVersion) return false;
//method processes messages and if needed creates creates WcfElements which are added to every clients queue
return ifSuccess;
}
#endregion
#region private methods
private void MyEventHandler(object sender, ServiceEventArgs e)
{
try
{
_callback.ReceiveWcfElement(e.WcfElement);
}
catch (Exception ex)
{
}
}
#endregion
}
#endregion
Client side in a moment
#region Client class
[DataContract]
public class Client
{
#region Instance Fields
/// <summary>
/// The UserName
/// </summary>
[DataMember]
public string UserName { get; set; }
[DataMember]
public WcfElement ElementsVersions { get; set; }
private bool _isSynchronized;
public bool IsSynchronized
{
get { return _isSynchronized; }
set
{
_isSynchronized = value;
}
}
public bool IsSending { get; set; }
public bool IsReceiving { get; set; }
private List<WcfElement> ElementsQueue { get; set; }
public object LockObj { get; set; }
public void AddElementToQueue(WcfElement wcfElement, int position = -1)
{
try
{
lock (LockObj)
{
if (ElementsQueue == null) ElementsQueue = new List<WcfElement>();
if (position != -1 && position <= ElementsQueue.Count)
{
try
{
ElementsQueue.Insert(position, wcfElement);
}
catch (Exception e)
{
}
}
else
{
try
{
//dodaje na koncu
ElementsQueue.Add(wcfElement);
}
catch (Exception e)
{
}
}
}
}
catch (Exception e)
{
}
}
public WcfElement GetFirstElementFromQueue()
{
if (ElementsQueue == null) return null;
if (ElementsQueue.Count > 0)
{
var tmp = ElementsQueue[0];
ElementsQueue.RemoveAt(0);
return tmp;
}
return null;
}
#endregion
#region Ctors
/// <summary>
/// Assign constructor
/// </summary>
/// <param name="userName">The userName to use for this client</param>
public Client(string userName)
{
UserName = userName;
}
#endregion
}
#endregion
ProxySingletion:
[CallbackBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant, UseSynchronizationContext = false)]
public sealed class ProxySingleton : IClientCallback
{
#region Instance Fields
private static ProxySingleton _singleton;
public static bool IsConnected;
private static readonly object SingletonLock = new object();
private ServiceProxy _proxy;
private Client _myPerson;
private delegate void HandleDelegate(Client[] list);
private delegate void HandleErrorDelegate();
//main proxy event
public delegate void ProxyEventHandler(object sender, ProxyEventArgs e);
public static event ProxyEventHandler ProxyEvent;
//callback proxy event
public delegate void ProxyCallBackEventHandler(object sender, ProxyCallBackEventArgs e);
public static event ProxyCallBackEventHandler ProxyCallBackEvent;
#endregion
#region Ctor
/// <summary>
/// Blank constructor
/// </summary>
private ProxySingleton()
{
}
#endregion
#region Public Methods
#region IClientCallback implementation
public void ReceiveWcfElement(WcfElement wcfElement)
{
//process received data
//...
ReadyToReceive();
}
#endregion
public void ReadyToReceive()
{
try
{
if (bazaDanych.Dane.Client.IsSending) return;
var w = bazaDanych.Dane.Client.GetFirstElementFromQueue();
if (w != null)
{
SendWcfElement(w);
return;
}
_proxy.ReadyToReceive(bazaDanych.Dane.Client.UserName, source, ostatniTypWiadomosci);
}
catch (Exception)
{
IsConnected = false;
}
}
public static WcfElement CurrentWcfElement;
public bool SendWcfElement(WcfElement wcfElement)
{
if (bazaDanych.Dane.Client.IsReceiving)
{
bazaDanych.Dane.Client.AddElementToQueue(wcfElement);
return true;
}
bazaDanych.Dane.Client.IsSending = true;
foreach (var wcfElementSplited in WcfElement.SplitWcfElement(wcfElement, true))
{
CurrentWcfElement = wcfElementSplited;
try
{
var r = _proxy.SendWcfElement(wcfElementSplited);
CurrentWcfElement = null;
}
catch (Exception e)
{
IsConnected = false;
return false;
}
}
bazaDanych.Dane.Client.IsSending = false;
ReadyToReceive();
return true;
}
public void ListenForConnectOrReconnect(EventArgs e)
{
SendWcfElement(WcfElement.GetVersionElement());//send wcfelement for perform PerformDataSync
ReadyToReceive();
}
public static bool IsReconnecting;
public bool ConnectOrReconnect(bool shouldRaiseEvent = true)
{
if (IsReconnecting)
{
return IsConnected;
}
if (IsConnected) return true;
IsReconnecting = true;
bazaDanych.Dane.Client.IsReceiving = false;
bazaDanych.Dane.Client.IsSending = false;
bazaDanych.Dane.Client.IsSynchronized = false;
try
{
var site = new InstanceContext(this);
_proxy = new ServiceProxy(site);
var list = _proxy.Login(bazaDanych.Dane.Client, bazaDanych.Dane.UserPassword, bazaDanych.Dane.UserIsAuto, bazaDanych.Dane.UserIsSuperMode);
bazaDanych.Dane.UserRights.Clear();
bazaDanych.Dane.UserRights.AddRange(list);
IsConnected = true;
if (shouldRaiseEvent) ConnectOrReconnectEvent(null);
}
catch (Exception e)
{
IsConnected = false;
}
IsReconnecting = false;
return IsConnected;
}
}
#endregion
At the moment my app works like this:
After successful login every client sends WcfElements(which contains bunch of list with ids and versions of elements). Then it sends ReadyToReceive one way message which after login fires performsync method. That method prepares data for client and sends first of them using one way receive method. IF there is more than one wcfelement to send then only last one is marked as last. Client responds with ReadyToReceive after every successful receive from Server. All up to this point works quite well. Problem starts later. Mostly packages are lost (method receiveWcfElement). Server has marked that client is receiving and maybe processing message and is waitng for readytoreceive packet, which will never be send because of lost element.
I've made it like this because as far as I know client can't send and receive at the same time. I've tried this and got this problem:
If client send wcfElement with SendWcfElement method and server due to processing this element created another element which was supposed to be ssend back to client then client whoud have faulted proxy if callback was send before sendWcfElement returned true indicating that method was completed.
Now I wonder if it is possible for client to send and receive at the same time using two way methods ?
I ended up with to services(two connections). One for connection from client to server and another with callback which handles connection from server to client.