I got a Windows Phone project which are getting an list of a object that i call friend from an webservice using REST. The whole connection part works good the first time, the second time it fails. I get the same value from the method even tho i change the value in the database. Here is an example.
Users goes to an page
The right value is fetched from the database using an WCF service
I change the value in the database manually
User goes into the page again and the method for fetching the data is started again but it still gets the same result as the first time it fetched data from the webservice.
Any ideas?
Code:
HttpWebRequest request;
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
UpdateData();
}
public void UpdateData()
{
((App)App.Current).ShowProgressBar();
string uri = App.SERVICE_URI + "/GetFriends?userid=" + App.CurrentUserId;
request = (HttpWebRequest)HttpWebRequest.Create(new Uri(uri));
request.BeginGetResponse(new AsyncCallback(GetFriendsReadCallback), request);
}
private void GetFriendsReadCallback(IAsyncResult asynchronousResult)
{
List<Friend> friends;
HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState;
HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(asynchronousResult);
using (StreamReader streamReader1 = new StreamReader(response.GetResponseStream()))
{
string resultString = streamReader1.ReadToEnd();
var ser = new DataContractJsonSerializer(typeof(List<Friend>));
var stream = new MemoryStream(Encoding.Unicode.GetBytes(resultString));
DataContractJsonSerializer jsonSerializer = new DataContractJsonSerializer(typeof(List<Friend>));
friends = (List<Friend>)jsonSerializer.ReadObject(stream);
}
You are running into a caching issue, most likely. Either change your REST service to disable caching:
Response.Cache.SetCacheability(HttpCacheability.NoCache);
If you don't have access to the service code, you can append a changing dummy parameter to the end of your request URL (e.g. a GUID or DateTime.Now.Ticks).
Check out my answer here: WebClient in a WP7.1 app called only once
I'd run this in the emulator with fiddler2 operating - check what id being sent over http to find out if the call is being made second time, and if the correct answer is being sent back. Once you know whether the problem is client or server side then start debugging using breakpoints - where is the wrong value first picked up.
Related
I have tried to create a simple console application.
We have a call system from 8x8 that provide a web streaming API but their documentation is very limited and nothing in C#.
The api service streams call statuses in near real time and I would like to get that 'stream' and be able to read and process it in realtime if possible. The response or Content Type is 'text/html'. But the actual body of the response can be declared as json - sample below:
{"Interaction":{"attachedData":{"attachedDatum":[{"attachedDataKey":"#pri","attachedDataValue":100},{"attachedDataKey":"callingName","attachedDataValue":999999999999},{"attachedDataKey":"cha","attachedDataValue":99999999999},{"attachedDataKey":"cnt","attachedDataValue":0},{"attachedDataKey":"con","attachedDataValue":0},{"attachedDataKey":"med","attachedDataValue":"T"},{"attachedDataKey":"pho","attachedDataValue":9999999999},{"attachedDataKey":"phoneNum","attachedDataValue":9999999999},{"attachedDataKey":"tok","attachedDataValue":999999999}]},"event":"InteractionCreated","inboundChannelid":9999999999,"interactionEventTS":9999999,"interactionGUID":"int-15b875d0da2-DJOJkDhDsrh3AIaFP8VkICv9t-phone-01-testist","resourceType":0}}
I have seen several posts concerning httpClient and the GetAsync methods but none of these appear to work as they appear to be for calls when a response is made, not something that constantly has a response.
Using fiddler for the call it does not appear to close so the stream is constantly running, so fiddler does not display any data until a separate user or instance connects.
When I use a browser the content is 'streamed' to the page and updates automatically and shows all the content (as above).
The api contains authentication so when another client connects and retrieves data the connected client closes and finally I am able to see the data that was gathering.
This is the code so and does return the big stream when another client connects but ideally I want a real time response and appears to just get stuck in the GETASYNC method:
var response = await client.GetAsync(address, HttpCompletionOption.ResponseHeadersRead);
if (response.IsSuccessStatusCode)
{
var responseContent = response.Content;
string responseString = await responseContent.ReadAsStringAsync();
Console.WriteLine(responseString);
}
Hopefully that's enough information for one of you clever people to help me in my predicament.
I was also having an issue consuming their streaming API and the examples I found that worked with the Twitter and CouchBase streaming API's did not work with 8x8. Both Twitter and CouchBase send line terminators in their pushes so the solution relied on ReadLine to pull in the feed. Since 8x8 does not send terminators you'll need to use ReadBlock or better ReadBlockAsync.
The following code shows how to connect using credentials and consume their feed:
private static async Task StreamAsync(string url, string username, string password)
{
var handler = new HttpClientHandler()
{
Credentials = new NetworkCredential {UserName = username, Password = password},
PreAuthenticate = true
};
// Client can also be singleton
using (var client = new HttpClient(handler))
{
client.Timeout = TimeSpan.FromMilliseconds(Timeout.Infinite);
var request = new HttpRequestMessage(HttpMethod.Get, url);
request.Headers.Connection.Add("keep-alive");
using (var response = await client.SendAsync(
request,
HttpCompletionOption.ResponseHeadersRead))
{
using (var body = await response.Content.ReadAsStreamAsync())
{
using (var reader = new StreamReader(body))
{
while (!reader.EndOfStream)
{
var buffer = new char[1024];
await reader.ReadBlockAsync(buffer, 0, buffer.Length);
Console.WriteLine(new string(buffer));
}
}
}
}
}
}
My goal
I'm trying to read and write files from my webserver via C#.
Progress
So far, via PHP I made it to work that you can write to files with file_put_contents(). The saved files are text files, so you can easily read them. My C# program with responses works fine, and I get my desired values.
private string GetWarnInfo(string id)
{
try
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create($"http://example.com/{id}.txt");
request.Method = "GET";
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
return reader.ReadToEnd();
}
}
catch(Exception)
{
return null;
}
}
100% of the time it did not return null, which is a success.
The problem
Well, the writing. My PHP in example.php looks like this:
if (file_exists($_GET['id'] . '.txt'))
{
unlink($_GET['id'] . '.txt');
file_put_contents($_GET['id'] . '.txt', $_GET['info']);
} else {
file_put_contents($_GET['id'] . '.txt', $_GET['info']);
}
While it fully works via browser calls (http://example.com/example.php?id=23&info=w3), and actually makes the text file, I can't get it to work with C#:
public void ServerRequest(string id, string info)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://example.com/example.php?id=" + id + "&info=" + info);
request.Method = "GET";
}
For example, I call ServerRequest((23).ToString(), "w3"), but the file won't change, it will always be either non-existant or in it last state (if there was one).
What could cause this problem? How would I fix it?
Thanks to #Barmar
I have figured out the problem, if I don't call GetResponse(), it will never start the web request. After doing that, everything worked fine!
I've been working on a project which makes use of an RTC API and forms authentication. I've hit a bit of bizarre behaviour and I just can't figure this one out.
The scenario that has played out to date is that I can successfully run this project locally end to end. That is, this specific piece of code can:
Contact the remote server and successfully authenticate
After authentication I'm able to pass XML to update a ticket in RTC
The problem starts when I publish to our IIS (7.5) server. All works fine right up until the last .GetResponse call which uses a PUT method to pass my XML to update the ticket in RTC. I keep getting 'The operation has timed out'.
I've spent literally days trying to figure this one out doing all manner of things but nothing has proved useful.
As a test I changed the PUT method on the second call to a GET. And it works! If I used a PUT with the .AllowAutoRedirect = false it works in that I get a response back, but then nothing happens on the RTC side so the request is clearly being ignored. I also noticed that the status being returned is marked as 'Found' instead of 'OK'.
Some people thought at this stage perhaps it was a lack of connectivity between the remote server and the web server. This wouldn't be the case as authentication works and this happens against the same server. I have also manually passed the XML / PUT call using the RESTClient on the web server which was accepted fine.
I just can't understand why it works end to end when running locally, but plays up once deployed to IIS?
I tried using log tracing and I'm not entirely sure if I'm getting anything useful from it. It might be totally unrelated but I can see this in the log that is generated on the IIS server:
<EventData>
<Data Name="ContextId">{00000000-0000-0000-12AF-0080000000F8}</Data>
<Data Name="ModuleName">ManagedPipelineHandler</Data>
<Data Name="Notification">128</Data>
<Data Name="HttpStatus">500</Data>
<Data Name="HttpReason">Internal Server Error</Data>
<Data Name="HttpSubStatus">0</Data>
<Data Name="ErrorCode">0</Data>
<Data Name="ConfigExceptionInfo"></Data>
</EventData>
As I say, I'm not sure if this is even related to the problem I'm having, but rather than ignore it I thought I'd share.
Code that forms the call (excuse the standard of coding, it's work in progress and got messy trying out different things to fix this problem)
//Setup webrequest
CookieContainer _cookies = new CookieContainer();
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(getPath);
var test44 = test4.ToString();
request.CookieContainer = _cookies;
request.ContentType = "application/rdf+xml";
request.Accept = "application/rdf+xml";
request.Method = "PUT";
request.AllowAutoRedirect = true;
request.AllowWriteStreamBuffering = true;
request.Timeout = 40000;
byte[] bytes = Encoding.ASCII.GetBytes(test44);
request.ContentLength = bytes.Length;
Stream dataStream = request.GetRequestStream();
dataStream.Write(bytes, 0, bytes.Length);
dataStream.Close();
//Pass request
logger.Info("Made it up to start of RTC request for secure document.");
using (HttpWebResponse getrespn = requestSecureDocument(request, "https://myserver:9100/jazz", "username", "pass", test44))
{
//Stream ReceiveStream = getrespn.GetResponseStream();
// Encoding encode = System.Text.Encoding.GetEncoding("utf-8");
//StreamReader readStream = new StreamReader(ReceiveStream);
//response = readStream.ReadToEnd();
getrespn.Close();
}
The segment of code which interacts with the RTC server (based on the example from: https://nkumar83.wordpress.com/2013/06/13/consuming-rtc-rational-team-concert-oslc-apis-using-c-post-1-authentication/ with my own tweaks):
public static HttpWebResponse requestSecureDocument(HttpWebRequest _requestItem, string _rtcServerURL, string _userName, string _password, string passXml)
{
try
{
//FormBasedAuth Step 1: Request the resource
HttpWebRequest _request = (HttpWebRequest)WebRequest.Create(_requestItem.RequestUri);
_request.CookieContainer = _requestItem.CookieContainer;
//store the response in _docResponse variable
HttpWebResponse _docResponse = (HttpWebResponse)_request.GetResponse();
//HttpStatusCode.OK indicates that the request succeeded
if (_docResponse.StatusCode == HttpStatusCode.OK)
{
//X-com-ibm-team... header signifies form based authentication is being used
string _rtcAuthHeader = _docResponse.Headers["X-com-ibm-team-repository-web-auth-msg"];
if ((_rtcAuthHeader != null) && _rtcAuthHeader.Equals("authrequired"))
{
_docResponse.GetResponseStream().Flush();
_docResponse.Close();
//Prepare form for authentication
HttpWebRequest _formPost = (HttpWebRequest)WebRequest.Create(_rtcServerURL + "/j_security_check");
_formPost.Method = "POST";
_formPost.Timeout = 30000;
_formPost.CookieContainer = _request.CookieContainer;
_formPost.Accept = "text/xml";
_formPost.ContentType = "application/x-www-form-urlencoded";
string _authString = "j_username=" + _userName + "&j_password=" + _password;
Byte[] _outBuffer = Encoding.UTF8.GetBytes(_authString);
_formPost.ContentLength = _outBuffer.Length;
Stream _str = _formPost.GetRequestStream();
_str.Write(_outBuffer, 0, _outBuffer.Length);
_str.Close();
//FormBasedAuth Step 2: Submit the login form and get response
HttpWebResponse _formResponse = (HttpWebResponse)_formPost.GetResponse();
_rtcAuthHeader = _formResponse.Headers["X-com.ibm-team.repository-web-auth-msg"];
//Check if auth failed
if ((_rtcAuthHeader != null) && _rtcAuthHeader.Equals("authfailed"))
{
//auth fialed
var fail = "";
}
else
{
//login successful
//FormBasedAuth Step 3: Resend the request for the protected resource
_formResponse.GetResponseStream().Flush();
_formResponse.Close();
using (HttpWebResponse getresp = (HttpWebResponse)_requestItem.GetResponse()) *** THIS IS TH LINE WHICH THROWS THE EXCEPTION ***
{
return getresp;
}
}
}
}
return _docResponse;
}
catch (WebException e)
{
var filePath = AppDomain.CurrentDomain.GetData("DataDirectory") + #"/trapA.xml";
using (StreamWriter writer = new StreamWriter(filePath, true))
{
writer.WriteLine("Message: Failed to trigger getresponse successfully: " + e);
}
}
return null;
}
Hope someone out there can help :o)
Well I'm pleased to say I've finally got to the bottom of this one. Turns out the problem wasn't anything to do with IIS and does actually work when published 'if' I'm not using the RTC client to make updates to a ticket.
The short story is that our RTC client uses a custom script to post out to our web api. However the RTC client appears to put a record lock on the ticket your trying to update which is persisted until a response from our API is provided. Of course this can't happen because part of the response is to confirm if the update was successful which can't happen due to the lock made by the RTC client.
The solution was to get the call in from RTC closed as quickly as possible. So the segment of code which authenticates and calls back out to RTC to make updates is now wrapped around with some new code to create a new thread. This has allowed the connection to be closed in about 5 seconds, all the while our app continues to make the necessary calls to complete the transaction.
Thread t = new Thread(() = > {
//code here
}
I may well be approaching this incorrectly, but what I'm trying to do is consume a GET request so I can manipulate the response into a format that I want. I need to be able to launch this from a browser, so I thought about building another RESTful service for this purpose.
i.e. Service ABC returns a string using a GET request. I want to take that string, do some manipulation and return it. I still need to be able to launch from a browser, so what I'm planning is to create a RESTful service XYZ, where the GET request in XYZ launches a call to the GET request of ABC, takes that response, converts it into my collection, and returns that collection. I'll then display in MVC.
Firstly: is this a dumb choice? I don't know a lot about different types of services.
Secondly: I have been able to get the ABC service data using a Console client, but not using a web-based client or service. Is this to be expected?
Code:
string webPath = #"http://ABCService.co.uk/";
string methodCall = #"methodABC/uid";
RestClient restClient = new RestClient(webPath);
RestRequest request = new RestRequest(methodCall, Method.GET);
var restResponse = restClient.Execute(request);
var content = restResponse.Content;
This works fine in the console (and I've actually been able to get the data just using a WebClient too), but neither method works from inside an MVC controller or service. I just get this as an ErrorException in restResponse:
Exception: "{"Unable to connect to the remote server" InnerException
= {"A connection attempt failed because the connected party did not properly respond after a period of time, or established connection
failed because connected host has failed to respond 80.64.52.36:80"}
Service ABC is up and running, can be accessed from a browser and console app. Note that I have no ability to alter any settings within Service ABC.
Many thanks
I resolved this by setting the proxy to null, rather than using a default proxy.
public string ReadWebReport(string path)
{
string str = String.Empty;
HttpWebRequest Request = WebRequest.Create(path) as HttpWebRequest;
Request.Method = "GET"; //Or PUT, DELETE, POST
Request.ContentType = "application/x-www-form-urlencoded";
Request.Proxy = null; //<-- inserted line
using (HttpWebResponse Response = Request.GetResponse() as HttpWebResponse)
{
if (Response.StatusCode != HttpStatusCode.OK)
throw new Exception("The request did not complete successfully and returned status code " + Response.StatusCode);
using (StreamReader Reader = new StreamReader(Response.GetResponseStream()))
{
str = Reader.ReadToEnd();
}
}
return str;
}
I have a web client I'm creating in Silverlight. I am trying to get it to communicate it with my web services on my server through GET and POST requests and JSON. The GET requests work fine and I'm able to parse the JSON on the Silverlight end. The POST requests however dont seem to work. The server reads that there is a POST request, but the POST array is empty.
Ive tried two pieces of code to send the POST requests, but both are resulting in the same response - an empty array.
The first Silverlight code I tried was:
public MainPage()
{
InitializeComponent();
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(new Uri("http://www.dipzo.com/game/services.php"));
request.Method = "POST";
request.ContentType = "application/json";
request.BeginGetRequestStream(new AsyncCallback(OnGetRequestStreamCompleted), request);
}
private void OnGetRequestStreamCompleted(IAsyncResult ar)
{
HttpWebRequest request = (HttpWebRequest)ar.AsyncState;
using (StreamWriter writer = new StreamWriter(request.EndGetRequestStream(ar)))
{
writer.Write("name=david");
}
request.BeginGetResponse(new AsyncCallback(OnGetResponseCompleted), request);
}
private void OnGetResponseCompleted(IAsyncResult ar)
{
//this.GetResponseCoimpleted.Visibility = Visibility.Visible;
// Complete the Flickr request and marshal to the UI thread
using (HttpWebResponse response = (HttpWebResponse)((HttpWebRequest)ar.AsyncState).EndGetResponse(ar))
{
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
string results = reader.ReadToEnd();
}
}
}
The second piece I tried was:
private void WebClient_Click(object sender, RoutedEventArgs e)
{
Test t1 = new Test() { Name = "Civics", Marks = 100 };
DataContractJsonSerializer jsondata = new DataContractJsonSerializer(typeof(Test));
MemoryStream mem = new MemoryStream();
jsondata.WriteObject(mem, t1);
string josnserdata = Encoding.UTF8.GetString(mem.ToArray(), 0, (int)mem.Length);
WebClient cnt = new WebClient();
cnt.UploadStringCompleted += new UploadStringCompletedEventHandler(cnt_UploadStringCompleted);
cnt.Headers["Content-type"] = "application/json";
cnt.Encoding = Encoding.UTF8;
cnt.UploadStringAsync(new Uri("http://www.dipzo.com/game/services.php"), "POST", josnserdata);
}
void cnt_UploadStringCompleted(object sender, UploadStringCompletedEventArgs e)
{
var x = e;
}
The code on the server to consume the service is in PHP and is essentially:
var_dump($_POST)
This should output whatever is coming into the post array. I've tested it with a simple PHP client and it works. Just can't get it to work in silverlight. In silverlight I just keep getting an empty array.
You should change the Content-type to application/x-www-form-urlencoded and not application/json which is not a known type yet.
Not that I think anyone is still paying attention tot his old question, but I'm betting that the problem was that it actually WAS getting to the server, but that the server routed the result back to the SL application. This is the behavior I'm seeing with a similar situation from SL5 usingWebClient.UploadStringAsync.
I'm about to implement/test a technique I ran across yesterday which uses a dynamically built, "real" page post from SL; I'll report my findings shortly.
UPDATE -- THIS SOLUTION WORKS:
http://www.codeproject.com/Tips/392435/Using-HTTP-Form-POST-method-to-pass-parameters-fro
I've just tested it in my application (SL5 inside MVC) and it works just fine. Make sure you check the HttpContext.Request.Form["fieldname"] to get the value(s) that you want. I used this technique to submit JSON and was able to return a generated Word document for the user.
Once I implemented this I was able to get rid of the unnecessary WebClient that I was attempting to use before.