MVVM Light making an HTTP Get request using Webapi - c#

I am a newbie when it comes to MVVM and Web related technologies. We are currently developing an MVVM client app using the latest MVVMLight framework in Visual Studios 2013. The application uses Microsoft's Webapi (latest version) to get data into our model via HTTP requests. Our code executes up to the point where the HTTP request is made, and we have confirmed that the server is getting the request, gathering up the requested data and returning it as JSON. However the client never sees the response, it just continues to wait for the response. Its almost as though we are seeing an issue that seems to do with threads. Where the request was made on one thread, but the response is being received on another. Here is our code (where the HTTP request is made):
public class DataService : IDataService
{
#region Fields
private HttpClient _client;
private LfActivityDataReturnObject _activityReturnObj;
private AdroServices _adroServices;
private bool _selectedProcssingOptionPosted = false;
private bool _activityDataSuccessfullyRetrieved = false;
private decimal _incomingLFEntryId;
#endregion
#region Constructor
public DataService()
{
try
{
//Get command line arguments
string[] arguments = Environment.GetCommandLineArgs();
for (int i = 1; i < arguments.Length; i++)
{
switch (i)
{
case 1:
{
if (!Decimal.TryParse(arguments[i], out _incomingLFEntryId))
{
_incomingLFEntryId = -1;
}
break;
}
}
}
if (_incomingLFEntryId <= 0)
{
throw new ArgumentException(String.Format("Invalid Activity Shortcut Entry ID: {0}", _incomingLFEntryId));
}
}
catch (Exception e)
{
throw e;
}
}
#endregion
#region Methods
public void GetGeneralInformationModel(Action<GeneralInformationModel, Exception> callback)
{
Exception locException = null;
GeneralInformationModel locGeneralInformationModel = null;
if (_adroServices == null)
{
try
{
//Start the HTTP request
GetActivityDataAsync().Wait();
}
catch (Exception e)
{
locException = e;
}
// change? should be for http success but adro failure
if (_activityDataSuccessfullyRetrieved)
{
_adroServices = new AdroServices(_activityReturnObj);
locGeneralInformationModel = new GeneralInformationModel(_adroServices);
}
else
{
Exception e2 = new Exception("Error retrieving activity data in DataService");
locException = e2;
}
}
else
{
locGeneralInformationModel = new GeneralInformationModel(_adroServices);
}
var item = locGeneralInformationModel;
callback(item, locException);
}
//Get data from the repository via the service layer.
private async Task GetActivityDataAsync()
{
try
{
using (this._client = new HttpClient())
{
_client.BaseAddress = new Uri("http://localhost:52512//");
_client.DefaultRequestHeaders.Accept.Clear();
_client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
//Line below is where the app just runs getting no response
HttpResponseMessage caseDataResponse = await _client.GetAsync(string.Format("api/LfUrs/{0}", _incomingLFEntryId));
if (caseDataResponse.IsSuccessStatusCode)
{
_activityReturnObj = await caseDataResponse.Content.ReadAsAsync<LfActivityDataReturnObject>();
if (_activityReturnObj.ReturnCode == 0)
{
_activityDataSuccessfullyRetrieved = true;
}
else
{
_activityDataSuccessfullyRetrieved = false;
}
}
else
{
_activityDataSuccessfullyRetrieved = false;
}
}
}
catch (Exception ex)
{
_activityDataSuccessfullyRetrieved = false;
throw ex;
}
}
We have tried using Fiddler to get more information but Fiddler doesn't seem to be able to reveal any of the details. Also I should mention that we are simulating the server on the local host and as I stated above, we have confirmed the server gets the request and returns the data. My associates and I are starting to think this has something to do with the MVVM Light Framework and the IOC or possibly threading. When we use this same code in a MVVM solution that doesn't use the framework it works. Any help would be sincerely appreciated. Thanks...Mike

I have figured it out. Somehow, in my app.xaml, the Dispatcher.Helper had been moved to the event On_Startup rather than being contained in the class constructor. Additionally I had to move the HTTP stuff into the ADRO services class and make sure it was constructed in the App constructor in app.xaml right after Dispatcher.Helper. But thanks to everyone who participates here on StackOverFlow. This resource is an absolute life-saver. Thanks

Related

Example implementation of IDuplexPipe for a TCP server

I've recently discovered the System.IO.Pipelines namespace and it looks interesting. I've been trying to implement the IDuplexPipe interface in the context of a simple TCP server which accepts connections and then communicates back and forth with the connected client.
However, I'm struggling to make it stable. It feels like I've misunderstood something fundamental. I've also been googling for reference implementations of the interface to guide me in the right direction.
This is to my knowledge the most complete document on System.IO.Pipelines out there. The exmple I've provided below is heavily borrowing from it.
https://github.com/davidfowl/DocsStaging/blob/master/Pipelines.md
https://devblogs.microsoft.com/dotnet/system-io-pipelines-high-performance-io-in-net/
My question: what would a typical implementation of the IDuplexPipe interface look like in the context of a TCP server?
Btw, this is what I have currently. The idea is to setup a new "duplex communication" by providing an established SslStream:
public class DuplexCommunication : IDuplexPipe
{
public PipeReader Input => _receivePipe.Reader;
public PipeWriter Output => _transmitPipe.Writer;
private readonly SslStream _stream;
// Data received from the SslStream will end up on this pipe
private readonly Pipe _receivePipe = new Pipe();
// Data that is to be transmitted over the SslStream ends up on this pipe
private readonly Pipe _transmitPipe = new Pipe();
private readonly CancellationToken _cts;
private Task _receive;
private Task _transmit;
public DuplexCommunication(SslStream stream, CancellationToken cts)
{
_stream = stream;
_cts = cts;
_receive = Receive();
_transmit = Transmit();
}
private async Task Receive()
{
Exception error = null;
try
{
while (!_cts.IsCancellationRequested)
{
var buffer = _receivePipe.Writer.GetMemory(1);
var bytes = await _stream.ReadAsync(buffer, _cts);
_receivePipe.Writer.Advance(bytes);
if (bytes == 0) {
break;
}
var flush = await _receivePipe.Writer.FlushAsync(_cts);
if (flush.IsCompleted || flush.IsCanceled)
{
break;
}
}
}
catch (Exception ex)
{
// This might be "stream is closed" or similar, from when trying to read from the stream
Console.WriteLine($"DuplexPipe ReceiveTask caugth an exception: {ex.Message}");
error = ex;
}
finally
{
await _receivePipe.Writer.CompleteAsync(error);
}
}
private async Task Transmit()
{
Exception error = null;
try
{
while (!_cts.IsCancellationRequested)
{
var read = await _transmitPipe.Reader.ReadAsync(_cts);
var buffer = read.Buffer;
if (buffer.IsEmpty && read.IsCompleted)
{
break;
}
foreach (var segment in buffer)
{
await _stream.WriteAsync(segment, _cts);
}
_transmitPipe.Reader.AdvanceTo(buffer.End);
await _stream.FlushAsync(_cts);
}
}
catch (Exception e)
{
Console.WriteLine($"DuplexPipe Transmit caught an exception: {e.Message}");
error = e;
}
finally
{
await _transmitPipe.Reader.CompleteAsync(error);
}
}
}
So, I spent some more time searching around the internet and found something that sort of solves my problem. I found, among some other things, this question: How to handle incoming TCP messages with a Kestrel ConnectionHandler?
Here it seems like the ConnectionHandler class provides exactly what I need, including some very handy plumbing for handling SSL certificates, port listening, etc that comes for free when building an ASP.NET application.

Why does a bound SUB receive only one message from a connecting PUB?

I'm making examples for my ZeroMQ CLR namespace, however I have a problem with PUB/SUB.
Why do I get only the first message? Sometimes I get no message, if I debug through the client (on PubSub_Client(arg);) I get some messages.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Security.Cryptography;
using ZeroMQ;
namespace ZeroMQ.Test
{
static partial class Program
{
static string PubSub_FrontendAddress = "tcp://127.0.0.1:2772";
public static void Main(string[] args)
{
if (args == null || args.Length < 1)
{
// say here were some arguments...
args = new string[] { "World" };
}
// Setup the ZContext
context = ZContext.Create();
CancellationTokenSource cancellor0 = null;
{
// Create the "Server" cancellor and threads
cancellor0 = new CancellationTokenSource();
var serverThread = new Thread(PubSub_Server);
serverThread.Start(cancellor0.Token);
serverThread.Join(64);
}
{
Thread.Sleep(1000);
Console.WriteLine("Starting...");
// foreach arg we are the Client, asking the Server
foreach (string arg in args)
{
PubSub_Client(arg);
// Thread.Sleep(1000);
}
Console.WriteLine("Ended...");
}
if (cancellor0 != null)
{
// Cancel the Server
cancellor0.Cancel();
}
// we could have done here context.Terminate()
}
static void PubSub_Server(object cancelluS)
{
var cancellus = (CancellationToken)cancelluS;
using (var socket = ZSocket.Create(context, ZSocketType.SUB))
{
socket.Bind(PubSub_FrontendAddress);
socket.SubscribeAll();
/* var poller = ZPollItem.Create(socket, (ZSocket _socket, out ZMessage message, out ZError _error) =>
{
while (null == (message = _socket.ReceiveMessage(/* ZSocketFlags.DontWait, * out _error)))
{
if (_error == ZError.EAGAIN)
{
_error = ZError.None;
Thread.Sleep(1);
continue;
}
throw new ZException(_error);
}
return true;
}); /**/
while (!cancellus.IsCancellationRequested)
{
ZError error;
ZMessage request;
/* if (!poller.TryPollIn(out request, out error, TimeSpan.FromMilliseconds(512)))
{
if (error == ZError.EAGAIN)
{
error = ZError.None;
Thread.Sleep(1);
continue;
}
throw new ZException(error);
} /**/
if (null == (request = socket.ReceiveMessage(ZSocketFlags.DontWait, out error)))
{
if (error == ZError.EAGAIN)
{
error = ZError.None;
Thread.Sleep(1);
continue;
}
throw new ZException(error);
} /**/
foreach (ZFrame frame in request)
{
string strg = frame.ReadString();
Console.WriteLine("{0} said hello!", strg);
}
}
socket.Unbind(PubSub_FrontendAddress);
}
}
static void PubSub_Client(string name)
{
using (var socket = ZSocket.Create(context, ZSocketType.PUB))
{
using (var crypto = new RNGCryptoServiceProvider())
{
var identity = new byte[8];
crypto.GetBytes(identity);
socket.Identity = identity;
}
socket.Connect(PubSub_FrontendAddress);
using (var request = new ZMessage())
{
request.Add(new ZFrame(name));
socket.Send(request);
}
socket.Disconnect(PubSub_FrontendAddress);
}
}
}
}
I'm having trouble with your design which seems just wrong:
A single subscriber and multiple publishers is an odd choice. I trust you have a good reason for it, but you should have said what that is. When sending messages from multiple clients to a single server, it is normal to use DEALER/ROUTER sockets instead. PUB/SUB is intended for a small set of publishers to a large number of subscribers.
A client that connects, sends one message, then immediately disconnects, is another very unusual use case that I hope is just an example:
For one thing, you are open to linger problems whereby the message will get dropped on the disconnect it is isn't sent within the linger timeout. [I don't know what the default linger is for your language binding, so that may or may not be an issue, but you should at least check to ensure that it isn't.]
For another, as you've already found, there are issues around the time it takes to connect to a socket, which may lead to PUB messages getting dropped if they are sent before the socket has properly connected.
If you insist on using PUB/SUB in this manner, you will need an out of band protocol to synchronise the PUB and SUB threads before the pub messages are sent. There are examples of how to do this reliable pub/sub in the zeromq guide. This will involve a second set of sockets in the same threads to send the synchronisation messages; DEALER sockets don't drop messages which is why they are suitable for that purpose...
But, DEALER/ROUTER sockets would appear to be a better choice than PUB/SUB unless there is some design requirement that hasn't been disclosed.
Well... There was a comment by Martin Sustrik: "The problem is that connecting is asynchronous and takes certain amount of time."
Now there is Thread.Sleep(64) - and it works...:
static void PubSub_Client(string name)
{
using (var socket = ZSocket.Create(context, ZSocketType.PUB))
{
socket.Connect(PubSub_FrontendAddress);
Thread.Sleep(64);
using (var request = new ZMessage())
{
request.Add(new ZFrame(name));
socket.Send(request);
}
socket.Disconnect(PubSub_FrontendAddress);
}
}
Do you know any better way to get the connection established?

Do not allow incoming call Lync Api or disabling sounds for incoming call

I have developed a windows application using Lync api. My client want to disable incoming calls to this application. So i have added some thing like this. I am able to cut the call but there are few rings before im able to do that
private void ClientInitialized(IAsyncResult result)
{
try
{
//registers for conversation related events
//these events will occur when new conversations are created (incoming/outgoing) and removed
client.ConversationManager.ConversationAdded += ConversationManager_ConversationAdded;
client.ConversationManager.ConversationRemoved += ConversationManager_ConversationRemoved;
}
catch (Exception ex)
{
MessageBox.Show("Problem in adding/removing conversation", "Bella IVIS", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
void ConversationManager_ConversationAdded(object sender, ConversationManagerEventArgs e)
{
try
{
var _client = client;
if (e.Conversation.State == ConversationState.Active)
{
for (int intLoop = 0; intLoop < _client.ConversationManager.Conversations.Count; intLoop++)
{
_client.ConversationManager.Conversations[intLoop].End();
}
_client = null;
return;
}
}
}
I do not know if there is a way to capture conversation before Conversation_Added event. However, if the Lync status is not of any relevance to you then you change the Lync Status to "Do not disturb". This way you would never get any incoming request (unless the user Lync setting allow to do so)
var newInformation =new Dictionary<PublishableContactInformationType, object>();
newInformation.Add(PublishableContactInformationType.Availability, ContactAvailability.DoNotDisturb);
try
{
this.lyncClient.Self.BeginPublishContactInformation(newInformation,(result) => this.lyncClient.Self.EndPublishContactInformation(result) , null);
} catch {}

Misbehaving Service behviors

Basically I'm making a program to simulate a petrol station system.
My problem is that I'm trying to send a request through a WCF service such as this:
User Requests Pump to be activated ----> WCF SERVICE ----> Point of Sale
User starts pumping petrol<---- WCF SERVICE <---- Point of Sale Accepts
At the moment it works, but only sometimes.
This is how I try to get a response:
while(PumpserviceClient.getRequestedAcceptedStatusFromPos().Accepted == false)
{
PumpserviceClient.RequestPump(int.Parse(PumpID));
// needs to wait for pump to be activated
if (PumpserviceClient.getRequestedAcceptedStatusFromPos().Accepted == true /*&& PumpserviceClient.getRequestedAcceptedStatusFromPos().PumpNo == int.Parse(PumpID)*/)
{
MessageBox.Show(" The Pos has accepted your pump request");
// if its accepted you call
Customer.ActivatePump();
}
And these are the methods in the service:
bool Accepted= false;
bool Requested=false;
public void AcceptPump(int PumpNumber)
{
Accepted = true;
Requested = false;
int pumpnumber = PumpNumber;
PumpRequest.Accepted = Accepted;
PumpRequest.Requested = Requested;
}
public void RequestPump(int PumpNumber)
{
int pumpnumber = PumpNumber;
Requested = true;
Accepted = false;
PumpRequest.Accepted = Accepted;
PumpRequest.PumpNo = PumpNumber;
PumpRequest.Requested = Requested;
}
public void ResetRequest(int PumpNumber)
{
int pumpnumber = PumpNumber;
Requested = false;
Accepted = false;
PumpRequest.Accepted = Accepted;
PumpRequest.PumpNo = 0;
PumpRequest.Requested = Requested;
}
public Message getRequestedStatusFromPump()
{
return PumpRequest;
}
public Message getRequestedAcceptedStatusFromPos()
{
return PumpRequest;
}
}
and the point of sale system accepts the requests by:
if (Client.getRequestedStatusFromPump().Requested == true)
{
MessageBox.Show("Pump Number: "+Client.getRequestedStatusFromPump().PumpNo + " Is waiting to be accepted");
// need to press a button or something
Client.AcceptPump(Client.getRequestedStatusFromPump().PumpNo);
}
Code here http://www.pastebucket.com/8642
I read the code posted. You use the following attribute:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
This means your code will not multi-thread. But there is no guarantee multiple sessions won't make requests and "interrupt" each other's workflow.
For example:
Client A calls request pump
Client B calls reset pump
Client A reads... client A wonders why pump was reset.
Your code is written expecting the object to be by session. I'd suggest using this context mode and seeing if you have better luck.
The other option is to add session information to your model. I can't imagine why this would be useful. It certainly won't be easy.
The only way i found around this problem, without changing service behaviors was to create a new list
public void CreatePumpList()
{
WaitingPumps = new List<WaitingPumps>();
for (int i = 0; i < PumpLimit+1 ; i++)
{
WaitingPumps.Add(new WaitingPumps());
}
}
Then just use the pump Number as the index in this list so they don't get confused with each other.

Keeping one wcf client proxy for whole app

I have highload ASP .NET MVC2 website and WCF service that site uses. Early I created one proxy every time I need it and even didn't close it. Refer to my previous question (with my big thanks for SO user Richard Blewett) I found out that I should close this proxy. In other way it will succeed sessions limit.
Now, I'm creating proxy one time app starts and then just check it and recreate it if is needed. So, here is the code:
public static bool IsProxyValid(MyServ.MyService client) {
bool result = true;
if ((client == null) || (client.State != System.ServiceModel.CommunicationState.Opened) // || (client.InnerChannel.State != CommunicationState.Opened)
)
result = false;
return result;
}
public static AServ.AServClient GetClient(HttpContext http) {
if (!IsProxyValid((MyService)http.Application["client"]))
http.Application["client"] = new MyService();
return (MyService)http.Application["client"];
}
public static MyServ.MyService GetClient(HttpContextBase http)
{
if (!IsProxyValid((MyService)http.Application["client"]))
http.Application["client"] = new MyService();
return (MyService)http.Application["client"];
}
public ActionResult SelectDepartment(string departments)
{
try
{
MyService svc = CommonController.GetClient(this.HttpContext);
Department[] depsArray = svc.GetData(departments);
// .... I cut here ....
return View();
}
catch (Exception exc)
{
// log here
return ActionUnavailable();
}
}
So, what do you guys think about it? Should it work properly? Sometimes my app stucked. I think it is because client proxy state determines uncorrectly and app tries to use broken proxy.
POST EDIT
Also in TCP Monitor I see a lot of established connections from site to service. Why it creates a lot of connectiong insteads of using one global? Maybe some exception occured while invoking service method makes it faulted state?
Hope for your help guys!
I think you need to abort the channel if it gets faulted before creating a new one and
Make sure to close/ abort old client if you creating the new client, use something like this for that (this one is used with DI in singleton)
public class MyServiceClientInitializer : IMyServiceClientInitializer
{
[ThreadStatic]
private static MyServ.MyService _client;
public MyServ.MyService Client
{
get
{
if (_client == null
|| (_client.State != CommunicationState.Opened
&& _client.State != CommunicationState.Opening))
IntializeClient();
return _client;
}
}
private void IntializeClient()
{
if (_client != null)
{
if (_client.State == CommunicationState.Faulted)
{
_client.Abort();
}
else
{
_client.Close();
}
}
string url = //get url;
var binding = new WSHttpBinding();
var address = new EndpointAddress(url);
_client = new MyServ.MyService(binding, address);
}
}

Categories