WCF service server throws an exception Cannot access a disposed object - c#

So my service is a simple chat application between two wcf clients. Event callback works when I call events. After I close my client and run it again, and write a message again (to call the event) it throws me exception:
An exception of type 'System.ObjectDisposedException' occurred in
RussianRouletteServiceLibrary.dll but was not handled in user code
Additional information: Cannot access a disposed object.
The code for my service callback is as follows:
private static Action<User, UMessage> gameChat = delegate { };
public void Play()
{
IGameCallback subscriber =
OperationContext.Current.GetCallbackChannel<IGameCallback>();
gameChat += subscriber.PlayerSentMessage;
}
This is the event trigger:
public void SendMessage(User user, UMessage message)
{
try
{
gameChat(user, message);
}
catch (Exception ex)
{
throw ex;
}
}
I get this error every time I .ChannelFactory.Close(); .Close(); the client while closing form event is happening.
Is there anyone that knows how to fix this and is willing to share his knowledge?
Thank you in advance!
EDIT #1
This is the code of the client when it opens:
ConcurrencyMode.Multiple,
UseSynchronizationContext = false)]
public partial class GameForm : Form, IGameCallback
{
#region IGame Callbacks
public void PlayerSentMessage(User user, UMessage message)
{
string nickname = user.NickName == clientUser.NickName ? "You" : user.NickName;
this.Invoke(new MethodInvoker(() => lb_ChatBox.Items.Add(nickname + " : " + message.MessageContent)));
}
#endregion
private GameClient _gameClient = null;
private InstanceContext _instance = null;
private User clientUser = new User(){ Email = "zigm4s#gmail.com", Id = 0, FirstName = "Zigmas", LastName = "Slusnys", NickName = "Ziggy", Password = "test123"};
public GameForm()
{
string state;
if (_gameClient != null)
{
MessageBox.Show("nelygu null");
MessageBox.Show(_gameClient.State.ToString());
//_gameClient = new GameClient(new InstanceContext(this));
}
else
{
_gameClient = new GameClient(new InstanceContext(this));
MessageBox.Show(_gameClient.State.ToString());
}
InitializeComponent();
try
{
_gameClient.Open();
_gameClient.Play();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
This is when the client form is closing.
private void GameForm_FormClosing(object sender, FormClosingEventArgs e)
{
try {
if (_gameClient.State != System.ServiceModel.CommunicationState.Faulted)
{
MessageBox.Show("Closing client");
_gameClient.ChannelFactory.Close();
_gameClient.Close();
}
else
{
MessageBox.Show("Aborting client");
_gameClient.Abort();
}
}
catch(Exception ex)
{ MessageBox.Show(ex.ToString());}
}
EDIT #2
I found the mistake, on the service side i had delegates that were static. It doesn't throw this error when it's not static.

Related

UWP AppServiceConnection - SendResponseAsync returns AppServiceResponseStatus.Failure

I'm trying to create a UWP service app on the Raspberry Pi3 which provides the access to the on board UART. I'm facing an issue about the AppConnection Request/response.
this is the service method that handles the incoming requests from client apps
internal class Inbound
{
public static async void OnRequestReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args)
{
var messageDeferral = args.GetDeferral();
var response = new ValueSet();
bool success = false;
var msg = args.Request.Message.Keys;
if (args.Request.Message.TryGetValue(ServiceApiRequests.Keys.Command, out object command))
{
try
{
switch (command)
{
case ServiceApiRequests.CommandValues.UartWrite:
if (args.Request.Message.TryGetValue(ServiceApiRequests.Keys.UartTxBuffer, out object txBuffer))
{
string rxBuff = "";
success = await Pi3.Peripherals.Uart.GerInstance(57600).Write((string)txBuffer);
if (success)
{
Debug.WriteLine("Tx: " + (string)txBuffer);
if (args.Request.Message.TryGetValue(ServiceApiRequests.Keys.ReadUartResponse, out object getResponse))
{
if ((string)getResponse == ServiceApiRequests.ReadUartResponse.Yes)
{
rxBuff = await Pi3.Peripherals.Uart.GerInstance(57600).Read();
Debug.WriteLine("Rx: " + rxBuff);
}
}
}
response.Add(ServiceApiRequests.Keys.UartRxBuffer, rxBuff);
}
break;
}
}
catch (Exception ex)
{
success = false;
}
}
response.Add(new KeyValuePair<string, object>(ServiceApiRequests.Keys.Result, success ? ServiceApiRequests.ResultValues.Ok : ServiceApiRequests.ResultValues.Ko));
var result = await args.Request.SendResponseAsync(response);
if (result == AppServiceResponseStatus.Failure)
{
Debug.WriteLine("Failed to send the response");
}
messageDeferral.Complete();
}
}
As you can figure out, the Uart class is get using the Singleton pattern using the method Pi3.Peripherals.Uart.GerInstance(57600).
Following the code i using for send the request from the client app.
public static class Uart
{
public static IAsyncOperation<string> SendCommand(this AppServiceConnection DriverControllerConnection, string txBuffer, string awaitResponse = ServiceApiRequests.ReadUartResponse.Yes)
{
return _SendCommand(DriverControllerConnection, txBuffer, awaitResponse).AsAsyncOperation();
}
private static async Task<string> _SendCommand(AppServiceConnection DriverControllerConnection, string txBuffer, string awaitResponse)
{
AppServiceResponse response = null;
string response_str = "";
try
{
if (DriverControllerConnection != null)
{
response = await DriverControllerConnection.SendMessageAsync(new ServiceApiRequests.UartWrite().GetCommand(txBuffer, awaitResponse));
if (response.Status == AppServiceResponseStatus.Success)
{
if (response.Message.TryGetValue(ServiceApiRequests.Keys.Result, out object result))
{
if ((string)result == ServiceApiRequests.ResultValues.Ok && awaitResponse == ServiceApiRequests.ReadUartResponse.Yes)
{
response_str = response.Message[ServiceApiRequests.Keys.UartRxBuffer] as string;
}
}
}
}
}
catch (Exception ex)
{
// TODO: log
}
return response_str;
}
}
The system works well just for a while, until i have response.Status == AppServiceResponseStatus.Success , then the result of the request changes and it becomes AppServiceResponseStatus.Failure. This way the program counter never steps into the condition if (response.Status == AppServiceResponseStatus.Success).
Any idea about the cause?
Thank you so much for the help.
EDIT
Follow the suggestions, i added an handler for the ServiceClosed event. This is the main class.
public sealed class DriverListener : IBackgroundTask
{
private BackgroundTaskDeferral backgroundTaskDeferral;
private AppServiceConnection appServiceConnection;
public void Run(IBackgroundTaskInstance taskInstance)
{
backgroundTaskDeferral = taskInstance.GetDeferral();
// taskInstance.Canceled += OnTaskCanceled;
var triggerDetails = taskInstance.TriggerDetails as AppServiceTriggerDetails;
appServiceConnection = triggerDetails.AppServiceConnection;
appServiceConnection.RequestReceived += Inbound.OnRequestReceived;
appServiceConnection.ServiceClosed += OnTaskCanceled;
}
private void OnTaskCanceled(AppServiceConnection sender, AppServiceClosedEventArgs reason)
{
if (this.backgroundTaskDeferral != null)
{
Debug.WriteLine("ServiceClosed");
// Complete the service deferral.
this.backgroundTaskDeferral.Complete();
}
}
}
Placing a breakpoint in this function, i see that it was never triggered.
The app connection is opened using the singleton pattern, and putted in a dll that i use in the client app
public static AppServiceConnection GetDriverConnectionInstance()
{
if (_DriverConnectionInstance == null)
{
try
{
_DriverConnectionInstance = OpenDriverConnection().AsTask().GetAwaiter().GetResult();
}
catch
{
}
}
return _DriverConnectionInstance;
}
I also add a Request to the service that toggles a led, and i noticed that the led status changes but the response from the app service is still "Failure" and the message is null.
The AppService has a default lifetime of 25sec, unless it is being requested by the foreground experience. When the service shuts down the connection, your client process will receive the ServiceClosed event, so you know you will need to reopen the connection the next time you want to send a request.

The connection to the OPC server drops after first connection throurg the WCF service

I have a WCF service as an OPC client that interfaces with an OPC DA server, also I have a WCF client that interacts with WCF and launches it (uses its methods)
The problem is that:
When I use WCF method connectToOPC() at first time, the connection can be break after few seconds, or not. DataChange stops coming.
But when I restart connectToOPC, the connection remains active and does not fall. What happens and why?
WCF Service:
public void connectToOPC(string OPCUrl, int GroupUpdateTime)
{
try
{
Main(OPCUrl, GroupUpdateTime);
}
catch (Exception ex) { Log(ex.Message, ""); }
}
public bool Run(string OPCUrl, int GroupUpdateTime)
{
try
{
url = new Opc.URL(OPCUrl);
server.Connect(url, new Opc.ConnectData(new System.Net.NetworkCredential()));
groupState = new Opc.Da.SubscriptionState();
groupState.Name = "MyGroup";
groupState.UpdateRate = GroupUpdateTime;
groupState.Active = true;
groupRead = (Opc.Da.Subscription)server.CreateSubscription(groupState);
groupRead.DataChanged += new Opc.Da.DataChangedEventHandler(group_DataChanged);
items = new Opc.Da.Item[ListOfTags.Count];
for (int i = 0; i < ListOfTags.Count; i++)
{
items[i] = new Opc.Da.Item();
items[i].ItemName = ListOfTags[i];
}
items = groupRead.AddItems(items);
}
catch (Exception ex)
{
Log(ex.Message, "");
return false;
}
return true;
}
void group_DataChanged(object subscriptionHandle, object requestHandle,Opc.Da.ItemValueResult[] values)
{
//its stops here at first time
}
And code of WCF client(WPF):
public partial class MainWindow : Window
{
OPCClient client;
public MainWindow()
{
InitializeComponent();
client = new OPCClient("BasicHttpBinding_IOPC");
}
private void buttonOpcRun_Click(object sender, RoutedEventArgs e)
{
try
{
GroupUpdateTime = Convert.ToInt32(textBoxUpdateGroupTime.Text);
client.connectToOPC(OPCUrl, GroupUpdateTime);
}
catch (Exception ex)
{
System.Windows.MessageBox.Show(ex + "");
}
}
}

Making throwing exceptions work

I've been trying to write a small program with these instructions:
In this assignment you should write a simple web application with one link on the front page of the web. If the link is clicked, the user will simply be routed to the front page again (using RedirectToAction). However, occasionally, the action method might throw an exception (but not always). Occasionally (one in every 5 occasions) the method should throw an ArgumentException, and occasionally (again, in maybe 1 in a 5), it should throw a custom Exception object you should declare yourself, called MyApplicationException.
In HomeController I have:
public class HomeController : Controller
{
List<Logger> m_loggers = new List<Logger>();
protected override void OnException(ExceptionContext fc)
{
base.OnException(fc);
Exception ex = fc.Exception;
Logger.Instance.Log(ex);
}
public ActionResult Index()
{
string strLogFile = System.Configuration.ConfigurationManager.AppSettings["LogFile"];
string strEmail = System.Configuration.ConfigurationManager.AppSettings["Email"];
try
{
RedirectToAction("Index");
using(MailMessage message = new MailMessage())
{
message.To.Add(strEmail);
message.Subject = "Villuskilaboð";
message.Body = "Upp hefur komið villa frá Skilaverkefni 4!";
using(SmtpClient client = new SmtpClient())
{
client.EnableSsl = true;
client.Send(message);
}
}
}
catch(Exception ex)
{
Random r = new Random();
int rand = r.Next(1000);
if(rand % 5 == 0)
{
throw new System.ArgumentException("Randon villuskilaboð handa þér!");
}
Debug.WriteLine(ex.Message +
Environment.NewLine +
ex.StackTrace);
}
return View();
}
Logger class:
public class Logger
{
List<LogMedia>m_loggers = new List<LogMedia>();
private static Logger theInstance = null;
public static Logger Instance
{
get
{
if (theInstance == null)
{
theInstance = new Logger();
}
return theInstance;
}
}
private Logger()
{
m_loggers = new List<LogMedia>();
//m_loggers.Add(new TextFileLogMedia { });
//m_loggers.Add(new EmailLogMedia { });
}
public void Log(Exception ex)
{
foreach(LogMedia log in m_loggers)
{
log.LogMessage(ex.Message + Environment.NewLine);
}
}
}
LogMedia
public class LogMedia
{
public virtual void LogMessage(string Message)
{
}
public class OutputWindowLogMedia: LogMedia
{
public override void LogMessage(string Message)
{
System.Diagnostics.Debug.WriteLine(Message);
}
}
public class TextFileLogMedia: LogMedia
{
public override void LogMessage(string Message)
{
//File.AppendAllText("c:\\Temp.Log.txt", Message);
}
}
public class EmailLogMedia: LogMedia
{
public override void LogMessage(string Message)
{
}
}
}
I´m stuck for now and seems not getting it to work, my Visual Studio crash and I get error up, don't think that is the exception, I´m so new to it so maybe it´s the box that should come up :) But the email never get to my account.
What am I still missing to make everything work? I know the file-thing isn't in this code, trying to make the other things to work first.
I've added information about my eMail in web.config.
You really need to rework your Index() method. I'm not in front of my computer with Visual Studio, but I'm surprised you code gets past the first line in your try. Having the RedirectToAction("Index") should throw a warning that the rest of the method will never be reached, and create an infinite loop when you try to access the method. The RedirectToAction("Index")` you have in your code does nothing as you don't return the results of that. Thank you Erik Noren
This would be how I'd structure your method instead:
public ActionResult Index() {
// No need to go higher, as it's always just as random with a modulo
int rnd = (new Random()).Next(5);
try {
switch (rnd) {
case 1: // Or any of the 5 numbers you want.
throw new ArgumentException();
case 4: // Again, any of the 5 numbers
throw new MyApplicationException();
default:
return RedirectToAction("Index");
}
}
catch (Exception ex) {
// Do your error logging here.
}
}

Quickfixn : How to write execution report to store file‏

I have created a application to send messages between client-server and I am having a
problem on server side.
I want to write the incoming NewOrderSingle message( .body extension file) files in store folder on server side.
The newordersingle message along with executionreport message get written into store file on client side. but on server side I don’t get application messages(file with .body extension) in store file.
How to write the incoming application messages to the file and not the admin messages.
My sample code is as follows:
public class clsFIXServer : QuickFix.MessageCracker, QuickFix.IApplication
{
public void FromApp(QuickFix.Message message, QuickFix.SessionID sessionID)
{
Console.WriteLine("IN: " + message);
Crack(message, sessionID);
}
public void OnCreate(QuickFix.SessionID sessionID)
{
}
public void OnLogon(QuickFix.SessionID sessionID)
{
}
public void OnLogout(QuickFix.SessionID sessionID)
{
}
public void ToAdmin(QuickFix.Message message, QuickFix.SessionID sessionID)
{
}
public void ToApp(QuickFix.Message message, QuickFix.SessionID sessionId)
{
Console.WriteLine("OUT: " + message);
}
public void OnMessage(QuickFix.FIX44.NewOrderSingle n, SessionID s)
{
Symbol symbol = n.Symbol;
Side side = n.Side;
OrdType ordType = n.OrdType;
OrderQty orderQty = n.OrderQty;
Price price = new Price(DEFAULT_MARKET_PRICE);
ClOrdID clOrdID = n.ClOrdID;
switch (ordType.getValue())
{
case OrdType.LIMIT:
price = n.Price;
if (price.Obj == 0)
throw new IncorrectTagValue(price.Tag);
break;
case OrdType.MARKET: break;
default: throw new IncorrectTagValue(ordType.Tag);
}
QuickFix.FIX44.ExecutionReport exReport = new QuickFix.FIX44.ExecutionReport(
new OrderID(GenOrderID()),
new ExecID(GenExecID()),
new ExecType(ExecType.FILL),
new OrdStatus(OrdStatus.FILLED),
symbol, //shouldn't be here?
side,
new LeavesQty(0),
new CumQty(orderQty.getValue()),
new AvgPx(price.getValue()));
exReport.Set(clOrdID);
exReport.Set(symbol);
exReport.Set(orderQty);
exReport.Set(new LastQty(orderQty.getValue()));
exReport.Set(new LastPx(price.getValue()));
if (n.IsSetAccount())
exReport.SetField(n.Account);
try
{
Session.SendToTarget(exReport, s);
}
catch (SessionNotFound ex)
{
Console.WriteLine("==session not found exception!==");
Console.WriteLine(ex.ToString());
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
}
My client side function that creates the newordersingle message :-
public void Run()
{
objEMSOrder = ((FIXFormatter.EMSOrder)messageQueue.Receive().Body);
if (this._session.SessionID.BeginString == "FIX.4.4")
{
QuickFix.FIX44.NewOrderSingle m = objMessageCreator.NewOrderSingle44MessageCreator(objEMSOrder);
**//DLL FUNCTION THAT CREATES MESSAGE**
if (m != null)
{
m.Header.GetField(Tags.BeginString);
SendMessage(m);
}
}
}
The message store is for internal use by the FIX session protocol. It only stores outgoing messages so that if there is a sequence gap is can resend previously sent messages. You want to look at the FileLogFactory and FileLog classes. Those will log both incoming and outgoing messages.

Capturing error if it occurs

How to do that if there is any error (anyone) to capture this error and write to a log ..
Recently a client changed the password webmaster (email used to authenticate messages sent)
And this meant that the system was no longer able to send emails.
The problem is that the error was not discovered days later.
Would you like a way to catch this error and save the message (email) and a log error, how?
In controller
new MailController(_subsidiaryService).PedidoOrcamentoEmail(model).DeliverAsync();
in MailController
public EmailResult PedidoOrcamentoEmail(BudgetViewModel model)
{
From = string.Format("{0} <{1}>", model.Name, model.Email);
To.Add("Site <" + ConfigurationManager.AppSettings["toEmail"] + ">");
var subInfo = (from s in _subsidiaryService.Repository.Query()
where s.ID == model.SubsidiaryID
select new
{
s.Title,
s.District
}).SingleOrDefault();
ViewData["SubsidiaryTitle"] = subInfo.Title;
ViewData["SubsidiaryDistrict"] = subInfo.District;
Subject = "[Pedido de Orçamento] " + model.Name;
return Email("PedidoOrcamentoEmail", model);
}
protected override void OnException(System.Web.Mvc.ExceptionContext filterContext)
{
// This is not executed
base.OnException(filterContext);
}
As a test, I put in an invalid password email webmaster (used for shipping)
Create a custom MailSender that inherits from the default MailSender and wrap the calls to the base methods in try..catch blocks. Then you can do anything with the exception when it occurs.
public class CustomMailSender : SmtpMailSender
{
private readonly ILog _log = LogManager.GetCurrentClassLogger();
public CustomMailSender() { }
public CustomMailSender(SmtpClient client) : base(client) { }
public new void Send(MailMessage mail)
{
try
{
base.Send(mail);
//Do some logging if you like
_log.Info(....)
}
catch (SmtpException e)
{
//Do some logging
var message = mail.RawMessageString();
_log.Error(message, e);
// rethrow if you want...
}
}
public new void SendAsync(MailMessage mail, Action<MailMessage> callback)
{
... similar ...
}
}
In your MailController the CustomMailSender is used like this:
public MailController() {
MailSender = new MyCustomMailSender();
}

Categories