EDIT: Here's my call stack.
System.ServiceModel.dll!System.ServiceModel.Channels.ServiceChannel.ThrowIfFaultUnderstood(System.ServiceModel.Channels.Message reply, System.ServiceModel.Channels.MessageFault fault, string action, System.ServiceModel.Channels.MessageVersion version, System.ServiceModel.Channels.FaultConverter faultConverter) + 0x124 bytes
System.ServiceModel.dll!System.ServiceModel.Channels.ServiceChannel.HandleReply(System.ServiceModel.Dispatcher.ProxyOperationRuntime operation, ref System.ServiceModel.Dispatcher.ProxyRpc rpc) + 0x147 bytes
System.ServiceModel.dll!System.ServiceModel.Channels.ServiceChannel.EndCall(string action, object[] outs, System.IAsyncResult result) + 0xb2 bytes
System.ServiceModel.dll!System.ServiceModel.ClientBase.ChannelBase.EndInvoke(string methodName, object[] args, System.IAsyncResult result) + 0x1e bytes
PhoneClient.dll!PhoneClient.ServiceReference1.Service1Client.Service1ClientChannel.EndGetFirstAidGuides(System.IAsyncResult result) Line 420 C#
PhoneClient.dll!PhoneClient.ServiceReference1.Service1Client.PhoneClient.ServiceReference1.IService1.EndGetFirstAidGuides(System.IAsyncResult result) Line 284 + 0x7 bytes C#
PhoneClient.dll!PhoneClient.ServiceReference1.Service1Client.OnEndGetFirstAidGuides(System.IAsyncResult result) Line 292 + 0x2 bytes C#
System.ServiceModel.dll!System.ServiceModel.ClientBase.OnAsyncCallCompleted(System.IAsyncResult result) + 0x20 bytes
System.ServiceModel.dll!System.ServiceModel.AsyncResult.Complete(bool completedSynchronously) + 0x66 bytes
System.ServiceModel.dll!System.ServiceModel.AsyncResult.Complete(bool completedSynchronously, System.Exception exception) + 0xe bytes
System.ServiceModel.dll!System.ServiceModel.Channels.ServiceChannel.SendAsyncResult.CallComplete(bool completedSynchronously, System.Exception exception) + 0x8 bytes
System.ServiceModel.dll!System.ServiceModel.Channels.ServiceChannel.SendAsyncResult.FinishSend(System.IAsyncResult result, bool completedSynchronously) + 0x99 bytes
System.ServiceModel.dll!System.ServiceModel.Channels.ServiceChannel.SendAsyncResult.SendCallback(System.IAsyncResult result) + 0x1a bytes
System.ServiceModel.dll!System.ServiceModel.AsyncResult.Complete(bool completedSynchronously) + 0x66 bytes
System.ServiceModel.dll!System.ServiceModel.AsyncResult.Complete(bool completedSynchronously, System.Exception exception) + 0xe bytes
System.ServiceModel.dll!System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelAsyncRequest.OnGetResponse(System.IAsyncResult result) + 0x52 bytes
System.Windows.dll!System.Net.Browser.ClientHttpWebRequest.InvokeGetResponseCallback.AnonymousMethod__8(object state2) + 0x1b bytes
mscorlib.dll!System.Threading.ThreadPool.WorkItem.WaitCallback_Context(object state) + 0x18 bytes
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state) + 0x63 bytes
mscorlib.dll!System.Threading.ThreadPool.WorkItem.doWork(object o) + 0x47 bytes
mscorlib.dll!System.Threading.Timer.ring() + 0x70 bytes
And the error: The server was unable to process the request due to an internal error. For more information about the error, either turn on IncludeExceptionDetailInFaults (either from ServiceBehaviorAttribute or from the configuration behavior) on the server in order to send the exception information back to the client, or turn on tracing as per the Microsoft .NET Framework 3.0 SDK documentation and inspect the server trace logs.
I'm currenntly working on a Windows Phone 7 application in which I am communicating with a WCF service. I've made it work within one method already. So I that it is possible.
Here is my class that calls the WCF service
public partial class FirstAidGuides : PhoneApplicationPage
{
public FirstAidGuides()
{
InitializeComponent();
ServiceReference1.Service1Client sc = new ServiceReference1.Service1Client();
sc.GetFirstAidGuidesCompleted += new EventHandler<ServiceReference1.GetFirstAidGuidesCompletedEventArgs>(sc_GetFirstAidGuidesCompleted);
sc.GetFirstAidGuidesAsync();
}
void sc_GetFirstAidGuidesCompleted(object sender, ServiceReference1.GetFirstAidGuidesCompletedEventArgs e)
{
FirstAidGuideText.Text = e.Result[0].Text;
}
}
Right now, I'm just trying to get some text written in a textblock, from my result.
This is the interface of the WCF service.
[ServiceContract]
public interface IService1
{
[OperationContract]
long CreateCall(string phoneNumber, double longtitude, double langtitude);
[OperationContract]
List<Model.FirstAidGuide> GetFirstAidGuides();
}
The method of my service class, that pulls data from a database.
public List<Model.FirstAidGuide> GetFirstAidGuides()
{
DataClasses1DataContext db = new DataClasses1DataContext();
var firstAidGuides = (from f in db.FirstAidGuides select f);
List<Model.FirstAidGuide> list = new List<Model.FirstAidGuide>();
foreach (var guide in firstAidGuides.ToList())
{
Model.FirstAidGuide fa = new Model.FirstAidGuide();
fa.FirstAidId = guide.FirstAidId;
fa.Title = guide.FirstAidTitle;
fa.Text = guide.FirstAidText;
fa.LastUpdated = (DateTime)guide.LastUpdated;
list.Add(fa);
}
return list;
}
And just for convenience. The FirstAidGuide class.
[DataContract]
public class FirstAidGuide
{
[DataMember]
private string _title;
[DataMember]
private string _text;
[DataMember]
private DateTime _lastUpdated;
[DataMember]
private long _firstAidId;
public long FirstAidId
{
get { return _firstAidId; }
set { _firstAidId = value; }
}
public DateTime LastUpdated
{
get { return _lastUpdated; }
set { _lastUpdated = value; }
}
public string Text
{
get { return _text; }
set { _text = value; }
}
public string Title
{
get { return _title; }
set { _title = value; }
}
}
I simply cannot get it to do anything. I'm getting a FaultException, which points me in the direction that it cannot handle the response from the WCF service.
Any help would be appreciated.
Can you try enabling tracing on your WCF Service and also inspect the trace to find out what the error is. Also set the below property to get a complete stack trace of the error
<serviceDebug includeExceptionDetailInFaults="true" />
What I tend to do over WCF is to wrap everything inside my [OperationContract] method in a Try...Catch block; unravel the stack trace of any caught exception and all inner exceptions and stick that as a string into the message of a FaultException that I then re-throw over the soap boundary. Something like this:
public static string GetDebugString(this Exception ex)
{
var builder = new StringBuilder();
GetDebugString(ex, builder);
while ((ex = ex.InnerException) != null)
{
GetDebugString(ex, builder);
}
return builder.ToString();
}
private static void GetDebugString(Exception ex, StringBuilder builder)
{
builder.AppendLine(ex.GetType().Name);
builder.AppendLine();
builder.AppendLine(ex.Message);
builder.AppendLine();
builder.AppendLine(ex.StackTrace);
builder.AppendLine();
}
[OperationContract]
public void Foo()
{
this.MakeSafeCall(() => this.UnsafeFoo());
}
public void Unsafe()
{
// do stuff
}
private void MakeSafeCall(Action action)
{
try
{
action();
}
catch (Exception ex)
{
throw new FaultException(ex.GetDebugString());
}
}
The problem was in this line:
foreach (var guide in firstAidGuides.ToList())
Apparently calling .ToList() made the whole thing crash.
Simply removing .ToList() fixed everything.
Related
I have a TCP server which send the data in the below format
------------|--------------------------------
---Header---| ----------- Data ----------
------------|--------------------------------
Header is of size 40 bytes of which first 2 bytes signifies the Data length and all the remaining bytes are 0 .
When the size of the data that needs to transfer from the server end is greater than 1500 the server sends the data in the following manner.
example: if length(data) == 1597
first transaction ->
-------|--------------------
|Header| data of length 1460
-------|--------------------
second transaction ->
|--------------------
data of length 147 (Note this transaction doesn't have header)
|--------------------
This is the process I'm following to read the data from the server on client end
First i read the header (40 bytes) and process this to get the data length to be read.
After get the data length i read "data-length" bytes to get the actual data.
The problem I'm facing is that this process works fine in my pc but when i test this other pcs it only works in debug mode (like when i step over each time). Other it only reads the first half of the message and discards the next part and throws this error.
System.Exception
HResult=0x80131500
Message=Exception occurred {0}
Source=SockTest
StackTrace:
at socketTest.sockTest.readData() in C:\usr\testing\SocketTransREcive\SockTest\sockTest.cs:line 125
at socketTest.main.testTrasRecv(sockTest sock, String command) in C:\usr\testing\SocketTransREcive\SockTest\Program.cs:line 13
at socketTest.main.testSend() in C:\usr\testing\SocketTransREcive\SockTest\Program.cs:line 51
at socketTest.main.Main(String[] args) in C:\usr\testing\SocketTransREcive\SockTest\Program.cs:line 63
This exception was originally thrown at this call stack:
[External Code]
socketTest.sockTest.readData() in sockTest.cs
Inner Exception 1:
ArgumentOutOfRangeException: Offset and length were out of bounds for the array or count is greater than the number of elements from index to the end of the source collection. (Parameter 'count')
I'm not sure what is causing the issue. I have checked the transactions on wire-shark and it seems server is sending them properly. Any help would be really appreciated!
Client Code
namespace socketTest
{
using System;
using System.Net;
using System.Net.Sockets;
public class sockTest : IDisposable
{
// defaults
private string ip = "192.168.1.100";
private int port = 1234;
//private int port = 16666;
public int error = -1;
public int noError = 0;
bool disposed = false;
private byte[] buffer;
private byte[] header;
// updated once instanciated
private IPAddress Ip;
public TcpClient socketHandle;
public NetworkStream tcpStream;
// instance check
private static readonly Lazy<sockTest> lazy = new Lazy<sockTest>(() => new sockTest());
private sockTest()
{
try
{
Console.WriteLine("Program started !");
this.Ip = IPAddress.Parse(ip);
}
catch (Exception exception)
{
//throw new Exception("Could not initialize socket erro : {0}", exception);
Console.WriteLine("Could not initialize socket error: {0}", exception);
}
}
public static sockTest Instance
{
get
{
return lazy.Value;
}
}
public int connect()
{
try
{
this.socketHandle = new TcpClient();
this.buffer = new byte[4000];
this.header = new byte[10];
this.socketHandle.Connect(this.Ip, this.port);
this.tcpStream = socketHandle.GetStream();
return noError;
}
catch (Exception exception)
{
Console.WriteLine(exception.ToString());
return error;
}
}
public int prcessHeader(byte[] header)
{
int ind = 0;
int flag = 0;
for (int i = 0; i < 10; i = i + 2)
{
int value = (header[i + 0]) | (header[i + 1] << 8);
if(flag == 0)
{
ind = value;
flag = 1;
}
}
return ind;
}
public string readData()
{
try
{
tcpStream.Read(this.header, 0, 10);
var inputString = System.Text.Encoding.ASCII.GetString(this.header);
//int msg_len = Int32.Parse(inputString);
int msg_len = prcessHeader(this.header);
tcpStream.Read(this.buffer, 0, msg_len);
return System.Text.Encoding.ASCII.GetString(this.buffer);
}
catch (Exception exception)
{
throw new Exception("Exception occurred {0}", exception);
//return null;
}
}
public int sendData(string data)
{
try
{
byte[] bData = System.Text.Encoding.ASCII.GetBytes(data);
tcpStream.Write(bData, 0, bData.Length * sizeof(byte));
return noError;
}
catch (Exception exception)
{
return error;
}
}
public void closeConnection()
{
tcpStream.Close();
this.socketHandle.Close();
}
public void Dispose()
{
// Dispose of unmanaged resources.
this.CheckDispose(true);
// Suppress finalization.
GC.SuppressFinalize(this);
}
protected virtual void CheckDispose(bool disposing)
{
if (disposed)
return;
if (disposing)
{
this.closeConnection();
}
disposed = true;
}
}
}
Here is the implementation of the comment
public string readData()
{
try
{
string tempRecv = "";
int len_read_msg = 0;
tcpStream.Read(this.header, 0, 10);
// your header parsing logic
int msg_len = processHeader(this.header);
if (msg_len > 1024)
{
len_read_msg = 1024;
}
else
{
len_read_msg = msg_len;
}
int tempRead = 0;
int compRead = 0;
while (compRead < msg_len)
{
Array.Clear(this.buffer, 0, this.buffer.Length);
tempRead = tcpStream.Read(this.buffer, 0, len_read_msg);
compRead = compRead + tempRead;
len_read_msg = msg_len - compRead;
var encoded = System.Text.Encoding.ASCII.GetString(this.buffer).Trim();
}
return tempRecv;
}
catch (Exception exception)
{
//throw new Exception("Exception occurred {0}", exception);
return null;
}
}
Cheers!
I'm trying to write a contract test using PactNet for the following method:
public async Task<IEnumerable<Models.RefData.Instrument> GetInstruments(string issuerCountry, string instrumentType)
{
ValidateNotNullOrWhiteSpaceParameter(issuerCountry, nameof(issuerCountry));
ValidateNotNullOrWhiteSpaceParameter(instrumentType, nameof(instrumentType)); ;
var queryString = $"instruments?issuerCountry={HttpUtility.UrlEncode(issuerCountry)}&instrumentType={HttpUtility.UrlEncode(instrumentType)}";
int pageNo = 0;
int pageSize = 20;
_logger.LogDebug($"GetInstruments Request:{queryString}");
var httpResponseMessage = await _client.GetAsync(queryString + $"&page={pageNo}&size={pageSize}");
_logger.LogDebug($"GetInstruments Response Status Code:{httpResponseMessage.StatusCode}");
switch (httpResponseMessage.StatusCode)
{
case HttpStatusCode.OK:
var content = await httpResponseMessage.Content.ReadAsStringAsync();
var result = JsonConvert.DeserializeObject<GetInstrumentsResponse>(content);
// if there are no results, return Empty
if (result.Metadata.TotalElements == 0)
{
return Enumerable.Empty<Models.RefData.Instrument>();
}
var instruments = new List<Models.RefData.Instrument>();
instruments.AddRange(result.Embedded.Instruments);
for (pageNo = 1; pageNo < result.Metadata.TotalPages; pageNo++)
{
var innerQueryString = queryString + $"&page={pageNo}&size={pageSize}";
_logger.LogDebug($"GetInstruments Request Additional Page:{innerQueryString}");
var httpResponseMessage2 = await _client.GetAsync(innerQueryString);
if (httpResponseMessage2.StatusCode != HttpStatusCode.OK)
{
_logger.LogError($"The requested page number {pageNo} gets response error {httpResponseMessage2.StatusCode.ToString()}.");
throw new UnexpectedResponseException(httpResponseMessage.StatusCode);
}
var content2 = await httpResponseMessage2.Content.ReadAsStringAsync();
var result2 = JsonConvert.DeserializeObject<GetInstrumentsResponse>(content2);
if (result2.Embedded.Instruments != null && result2.Embedded.Instruments.Any())
{
instruments.AddRange(result2.Embedded.Instruments);
}
}
if (instruments.Count != result.Metadata.TotalElements)
{
_logger.LogWarning($"Total number of instruments is different from MetaData. MetaData states {result.Metadata.TotalElements}, however only {instruments.Count} instruments retrieved.");
}
_logger.LogDebug($"GetInstruments Result:{instruments.ToJson()}");
return instruments;
default:
throw new UnexpectedResponseException(httpResponseMessage.StatusCode);
}
}
I created the following ConsumerPactTests.cs and ConsumerPactClassFixture.cs using this as a guide.
public class ConsumerPactTests : IClassFixture<ConsumerPactClassFixture>
{
private IMockProviderService _mockProviderService;
private string _mockProviderServiceBaseUri;
public ConsumerPactTests(ConsumerPactClassFixture fixture)
{
_mockProviderService = fixture.MockProviderService;
_mockProviderService.ClearInteractions(); //NOTE: Clears any previously registered interactions before the test is run
_mockProviderServiceBaseUri = fixture.MockProviderServiceBaseUri;
}
[Fact]
public void ItHandlesInvalidDateParam()
{
// Arange
var invalidRequestMessage = "issuerCountry or instrumentType is not valid";
_mockProviderService.Given("There is data")
.UponReceiving("A invalid GET request for Date Validation with invalid date parameter")
.With(new ProviderServiceRequest
{
Method = HttpVerb.Get,
Path = "/api/v2",
Query = "issuerCountry=USA&instrumentType=foo"
})
.WillRespondWith(new ProviderServiceResponse
{
Status = 400,
Headers = new Dictionary<string, object>
{
{ "Content-Type", "application/json; charset=utf-8" }
},
Body = new
{
message = invalidRequestMessage
}
});
// Act
RefDataHttpService sut = new RefDataHttpServiceBuilder().Build();
var result = sut.GetInstruments("USA", "foo").GetAwaiter().GetResult();
var resultBodyText = result.GetEnumerator();
// Assert
Assert.NotNull(resultBodyText);
}
}
public class ConsumerPactClassFixture : IDisposable
{
public IPactBuilder PactBuilder { get; private set; }
public IMockProviderService MockProviderService { get; private set; }
public int MockServerPort { get { return 9222; } }
public string MockProviderServiceBaseUri { get { return String.Format("http://localhost:{0}", MockServerPort); } }
public ConsumerPactClassFixture()
{
var pactConfig = new PactConfig
{
SpecificationVersion = "2.0.0",
PactDir = #"..\..\..\..\..\pacts",
LogDir = #".\pact_logs"
};
PactBuilder = new PactBuilder(pactConfig);
PactBuilder.ServiceConsumer("Consumer")
.HasPactWith("Provider");
MockProviderService = PactBuilder.MockService(MockServerPort);
}
#region IDisposable Support
private bool disposedValue = false; // To detect redundant calls
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
// This will save the pact file once finished.
PactBuilder.Build();
}
disposedValue = true;
}
}
// This code added to correctly implement the disposable pattern.
public void Dispose()
{
// Do not change this code. Put cleanup code in Dispose(bool disposing) above.
Dispose(true);
}
#endregion
}
When I run my test I get this error:
dotnet test --filter "FullyQualifiedName=Bond.Publisher.Tests.ContractTest.ConsumerPactTests.ItHandlesInvalidDateParam"
Test run for c:\Workspace\prod\test\Bond.Publisher.Tests\bin\Debug\netcoreapp3.1\Bond.Publisher.Tests.dll(.NETCoreApp,Version=v3.1)
Microsoft (R) Test Execution Command Line Tool Version 16.7.0
Copyright (c) Microsoft Corporation. All rights reserved.
Starting test execution, please wait...
A total of 1 test files matched the specified pattern.
[xUnit.net 00:00:10.95] Bond.Publisher.Tests.ContractTest.ConsumerPactTests.ItHandlesInvalidDateParam [FAIL]
X Bond.Publisher.Tests.ContractTest.ConsumerPactTests.ItHandlesInvalidDateParam [4s 196ms]
Error Message:
System.Net.Http.HttpRequestException : No connection could be made because the target machine actively refused it.
---- System.Net.Sockets.SocketException : No connection could be made because the target machine actively refused it.
Stack Trace:
at System.Net.Http.ConnectHelper.ConnectAsync(String host, Int32 port, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.ConnectAsync(HttpRequestMessage request, Boolean allowHttp2, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.CreateHttp11ConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.GetHttpConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage request, Boolean doRequestAuth, CancellationToken cancellationToken)
at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at Bond.Publisher.HttpMessageHandlers.UnoAuthorisationHeaderMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) in c:\Workspace\usprod\src\Bond.Publisher\HttpMessageHandlers\UnoAuthorisationHeaderMessageHandler.cs:line 37
at System.Net.Http.HttpClient.FinishSendAsyncBuffered(Task`1 sendTask, HttpRequestMessage request, CancellationTokenSource cts, Boolean disposeCts)
at Bond.Publisher.Services.RefDataHttpService.GetInstruments(String issuerCountry, String instrumentType) in c:\Workspace\prod\src\Bond.Publisher\Services\RefDataHttpService.cs:line 52
at Bond.Publisher.Tests.ContractTest.ConsumerPactTests.ItHandlesInvalidDateParam() in c:\Workspace\prod\test\Bond.Publisher.Tests\ContractTest\ConsumerPactTests.cs:line 52
----- Inner Stack Trace -----
at System.Net.Http.ConnectHelper.ConnectAsync(String host, Int32 port, CancellationToken cancellationToken)
Test Run Failed.
I suspect it may be some sort of authentication issue as UnoAuthorisationHeaderMessageHandler.cs deals with that. What have I done wrong with this?
For me the path was too long. When I moved the project to a folder closer to C:\ the test ran.
The System.Net.Sockets.SocketException : No connection could be made because the target machine actively refused it. usually happens when there is no server listening on the url you are sending.
Check if the ruby service is up and running (the test runner starts it), you should see it in Task Manager under Visual Studio
Alernatively, before you call pactBuilder.Build(), you should be able to do an HTTP request through PostMan to http://localhost:9222/instruments...
Stated another way, using HttpContext, how can I retrieve the parameters passed to a [WebMethod] when in a global error handler?
Kovu gives a great example of how to do a global error trap to grab [WebMethod] errors in Global.asax, which I think he got from Richard Liu here, but his solution does not capture the parameters passed to the WebMethod, and I really need to log these to repro the errors.
I adapted Richard/Kovu's example to start trapping more things about the request, but I just can't find where the input parameters for the [WebMethod] are hidden.
/* global.asax */
protected void Application_PostMapRequestHandler(object sender, EventArgs e)
{
/* REQUIRES
<system.web>
<customErrors mode="Off"/>
TO WORK IN PRODUCTION
*/
HttpContext context = HttpContext.Current;
if (context.Handler is Page && !string.IsNullOrEmpty(context.Request.PathInfo))
{
string contentType = context.Request.ContentType.Split(';')[0];
if (contentType.Equals("application/json", StringComparison.OrdinalIgnoreCase))
{
context.Response.Filter = new PageMethodExceptionLogger(context);
}
}
}
using System.Collections.Generic;
using System.IO;
using System.Web;
using System.Web.Script.Serialization;
public class PageMethodExceptionLogger : Stream
{
private readonly HttpContext _context;
private readonly Stream _baseStream;
private readonly MemoryStream _capturedStream = new MemoryStream();
public PageMethodExceptionLogger(HttpContext context)
{
_context = context;
_baseStream = context.Response.Filter;
}
public override void Close()
{
if (_context.Response.StatusCode == 500 && _context.Response.Headers["jsonerror"] == "true")
{
string sErr = "trapped json error, probably in [WebMethod]:\r\n\r\n";
//this will log the error and stack trace.
_capturedStream.Position = 0;
string responseJson = new StreamReader(_capturedStream).ReadToEnd();
JavaScriptSerializer js = new JavaScriptSerializer();
var jsonObject = js.DeserializeObject(responseJson) as Dictionary<string, object>;
foreach (string sKey in jsonObject.Keys)
sErr += string.Format("{0}:\r\n{1}\r\n\r\n", sKey, jsonObject[sKey]);
//============= LOG THE INPUT PARAMETERS ========================================================
sErr += "\r\n=== Request ===\r\n";
sErr += "Content Type = " + _context.Request.ContentType + "\r\n";
sErr += "Content Encoding = " + _context.Request.ContentEncoding.BodyName + "\r\n";
_context.Request.InputStream.Position = 0;
//========= this holds the parameters passed to the [WebMethod] ========
// It holds a JSON string, so could deserialize as above, but
// useful to see the original string format for debugging
// purposes, as the json format could be the issue that triggered this log!! ;-)
sErr += "\r\n=== INPUT ===\r\n";
try
{
long iReadLen = _context.Request.InputStream.Length;
if (iReadLen > 0)
{
var bytes = new byte[iReadLen];
_context.Request.InputStream.Position = 0;
_context.Request.InputStream.Read(bytes, 0, (int)iReadLen);
sErr += System.Text.Encoding.UTF8.GetString(bytes) + "\r\n";
}
else
{
sErr += "Request.InputStream is empty\r\n";
sErr += System.Text.Encoding.Default.GetString(_context.Request.BinaryRead(_context.Request.TotalBytes));
}
}
catch(Exception oEx)
{
sErr += "Error reading Request.InputStream; " + oEx.Message;
}
sErr += "\r\n=== HEADERS ===\r\n";
sErr += HttpUtility.UrlDecode(_context.Request.Headers.ToString()).Replace("&", "\r\n") + "\r\n";
sErr += "\r\n=== USER ===\r\n";
try
{
sErr += "Current User = " + _context.User.Identity.Name + "\r\n\r\n";
}
catch
{
sErr += "oContext.User.Identity.Name could not be retrieved!!!\r\n\r\n";
}
//====== LOG THE SESSION ========
sErr += "\r\n=== Session Variables ===\r\n";
if (_context.Session == null)
{
sErr += "session object is null\r\n";
}
else
{
sErr += "There are " + _context.Session.Count.ToString() + " session variables\r\n";
foreach (string sKey in _context.Session)
{
sErr += sKey + "=" + _context.Session[sKey].ToString() + "\r\n";
}
}
sErr += "\r\n";
clsErrorHandler.LogMessage(sErr);
}
_baseStream.Close();
base.Close();
}
public override void Flush()
{
_baseStream.Flush();
}
public override long Seek(long offset, SeekOrigin origin)
{
return _baseStream.Seek(offset, origin);
}
public override void SetLength(long value)
{
_baseStream.SetLength(value);
}
public override int Read(byte[] buffer, int offset, int count)
{
return _baseStream.Read(buffer, offset, count);
}
public override void Write(byte[] buffer, int offset, int count)
{
_baseStream.Write(buffer, offset, count);
_capturedStream.Write(buffer, offset, count);
}
public override bool CanRead { get { return _baseStream.CanRead; } }
public override bool CanSeek { get { return _baseStream.CanSeek; } }
public override bool CanWrite { get { return _baseStream.CanWrite; } }
public override long Length { get { return _baseStream.Length; } }
public override long Position
{
get { return _baseStream.Position; }
set { _baseStream.Position = value; }
}
}
Now this code gives the following output.
(the formatting is messed up because I can't figure out how to use the SO WYSIWYG editor, sorry).
============================================================ trapped json error, probably in [WebMethod]:
Message: Invalid object passed in, ':' or '}' expected. (23):
{'sKitName':'christin'a'}
StackTrace: at
System.Web.Script.Serialization.JavaScriptObjectDeserializer.DeserializeDictionary(Int32
depth) at
System.Web.Script.Serialization.JavaScriptObjectDeserializer.DeserializeInternal(Int32
depth) at
System.Web.Script.Serialization.JavaScriptObjectDeserializer.BasicDeserialize(String
input, Int32 depthLimit, JavaScriptSerializer serializer) at
System.Web.Script.Serialization.JavaScriptSerializer.Deserialize(JavaScriptSerializer
serializer, String input, Type type, Int32 depthLimit) at
System.Web.Script.Serialization.JavaScriptSerializer.Deserialize[T](String
input) at
System.Web.Script.Services.RestHandler.GetRawParamsFromPostRequest(HttpContext
context, JavaScriptSerializer serializer) at
System.Web.Script.Services.RestHandler.GetRawParams(WebServiceMethodData
methodData, HttpContext context) at
System.Web.Script.Services.RestHandler.ExecuteWebServiceCall(HttpContext
context, WebServiceMethodData methodData)
ExceptionType: System.ArgumentException
=== INPUT === {'sKitName':'christin'a'}
=== HEADERS === Connection=keep-alive Content-Length=25 Content-Type=application/json; charset=UTF-8 Accept=application/json,
text/javascript, /; q=0.01 Accept-Encoding=gzip, deflate
Accept-Language=en-US,en;q=0.9
Cookie=.ADAuthCookie=A12630A2F7FEA673C36FDC28C7625ED4C4C92760B0EEE6C68C8068FF81A8773DF1916B4A067326576F4D067D4C26C874A9C3C96D81F74D15E0452EDD743C3472F530DE5E6542E8DE1DD19BF76114702F70AF483DBF963C8686727CB541151EBF32322CD647ADD6D9FC01C4785393227F19341D2BE320DF821E0E223A24B7FBB5E5CA7F79D87815AF49AF24C455CA81FD;
ASP.NET_SessionId=iqc0ztobmcva4lqbtii222fa Host=web04.local
Referer=http://web04.local/APP/Chem_View/Reagent_Kit_Inventory.aspx
User-Agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64)
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132
Safari/537.36 Origin=http://web04.local
X-Requested-With=XMLHttpRequest
=== USER === Current User = lila.whitehead
=== Session Variables === There are 1 session variables dtTouched=
At 9/9/2019 2:37:00 PM
============================================================
Lets say I have this two functions:
private string otherString;
private void Error(string message) {
throw new Exception("Error: " + message);
}
private void Expected(string message) {
Error("Expected " + message + " got " + otherString);
}
Now I want to write code that looks like the this:
private int ReadInt() {
int result = 0;
if(int.TryParse(otherString, out result)) {
return result;
}
Expected("Int");
//return 0; is need to compile but it will be never reached
}
I understand that the compiler can not assume that by calling Expected the ReadInt function will end. Is there another way to do what I want to do without the need to write the throw statement in every place I want to exit with an Error?
throw new Exception("Error: Expected Digit got " + otherString);
Probably you are going to log/catch this exception later, here is the problem, With the current set up you will not know (directly) where the exception actually happened, from TargetSite you will only get information about method Error throwing exception and not the actual method ReadInt. (Although through Stack Trace you can see the call hierarchy and the ReadInt method).
Throw exception where ever you think it should be thrown, not from some generic method. Also instead of throwing base class exception, throw specific exceptions like InvalidArgumentException etc.
As a side note, if you are only concerned about parsing related exceptions then don't use TryParse group of methods and let the original exception bubble up.
Apart from what the other answers are saying (don't do that, it's not a good practice), you could simply "fool" the compiler by having the error-method return a fake value:
private string otherString;
private T Error<T>(string message) {
throw new Exception("Error: " + message);
return default(T);
}
private T Expected<T>(string message) {
return Error<T>("Expected " + message + " got " + otherString);
}
private int ReadInt() {
int result = 0;
if(int.TryParse(otherString, out result)) {
return result;
}
return Expected<int>("Int");
}
Another possibility (as suggested in the comments) is to return the exception and throw it in the method:
private string otherString;
private Exception Error(string message) {
return new Exception("Error: " + message);
}
private Expected(string message) {
return Error("Expected " + message + " got " + otherString);
}
private int ReadInt() {
int result = 0;
if(int.TryParse(otherString, out result)) {
return result;
}
throw Expected("Int");
}
Last, but not least, you can create your own exception and throw that one:
class ExpectedException : Exception
{
public ExpectedException(string message)
: base("Expected " + message + " got " + otherString)
{}
}
private int ReadInt() {
int result = 0;
if(int.TryParse(otherString, out result)) {
return result;
}
throw new ExpectedException("Int");
}
I'm working on a bigger project which uses WCF data service and OData to communicate between the frontend and the backend and we have performance problems when creating entities. Digging deeper into the problem uncovered that when the client tries to save a new entity then a query is executed in the service which returns all entities and it is discarded and then the data is inserted.
I was thinking that the problem is related how our application was created. It uses a custom provider, but the strange thing is that the problem occurs even with the simplest test project.
I have used the following code posted below and I set breakpoints inside Provider.cs. When I invoke it with HttpRequester Firefox plugin to send a POST request (insert) according to OData then
IQueryable gets called
CreateResource is called
SetValue is called several times
SaveChanges is called
I have the question why the IQueryable gets called and how it should be prevented? I was not able to figure that out.
In our real life scenario and not in this test app the IQueryable returns several thousand records, or even more, and can be time consuming. This impacts the performance of insert operations.
Request to insert a record
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<entry xml:base="http://localhost:50366/MyDataService.svc/" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns="http://www.w3.org/2005/Atom">
<id>http://localhost:50366/MyDataService.svc/Employees(0)</id>
<title type="text"></title>
<updated>2012-07-31T18:03:45Z</updated>
<author>
<name />
</author>
<link rel="edit" title="Employee" href="Employees(0)" />
<category term="Test.Dto.Employee" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
<content type="application/xml">
<m:properties>
<d:EmployeeID m:type="Edm.Int32">2</d:EmployeeID>
<d:LastName>Test</d:LastName>
<d:FirstName>Data</d:FirstName>
</m:properties>
</content>
</entry>
MyDataService.svc.cs:
using System;
using System.Collections.Generic;
using System.Data.Services;
using System.Data.Services.Common;
using System.Linq;
using System.ServiceModel.Web;
using System.Web;
namespace Test
{
public class MyDataService : DataService<Provider>
{
// This method is called only once to initialize service-wide policies.
public static void InitializeService(DataServiceConfiguration config)
{
config.SetEntitySetAccessRule("*", EntitySetRights.All);
config.SetServiceOperationAccessRule("*", ServiceOperationRights.All);
config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;
}
}
}
Employee.cs
using System.Data.Services.Common;
namespace Test.Dto
{
[DataServiceKey("EmployeeID")]
public class Employee
{
public virtual int EmployeeID { set; get; }
public virtual string LastName { set; get; }
public virtual string FirstName { set; get; }
}
}
Provider.cs
using System.Linq;
using Test.Dto;
using System.Collections.Generic;
using System.Data.Services;
namespace Test
{
public class Provider : IUpdatable
{
static IList<Employee> _employees = new List<Employee>() {
new Employee {
EmployeeID = 1,
FirstName = "No",
LastName = "Name"
}
};
IList<Employee> _updates = new List<Employee>();
public IQueryable<Employee> Employees
{
get
{
return Provider._employees.AsQueryable();
}
}
public void AddReferenceToCollection(object targetResource, string propertyName, object resourceToBeAdded)
{
throw new System.NotImplementedException();
}
public void ClearChanges()
{
_updates.Clear();
}
public object CreateResource(string containerName, string fullTypeName)
{
if (Equals(fullTypeName, typeof(Employee).FullName))
{
var entity = new Employee();
_updates.Add(entity);
return entity;
}
else
{
throw new System.NotImplementedException();
}
}
public void DeleteResource(object targetResource)
{
throw new System.NotImplementedException();
}
public object GetResource(IQueryable query, string fullTypeName)
{
throw new System.NotImplementedException();
}
public object GetValue(object targetResource, string propertyName)
{
throw new System.NotImplementedException();
}
public void RemoveReferenceFromCollection(object targetResource, string propertyName, object resourceToBeRemoved)
{
throw new System.NotImplementedException();
}
public object ResetResource(object resource)
{
throw new System.NotImplementedException();
}
public object ResolveResource(object resource)
{
return resource;
}
public void SaveChanges()
{
foreach (var item in _updates)
{
_employees.Add(item);
}
}
public void SetReference(object targetResource, string propertyName, object propertyValue)
{
throw new System.NotImplementedException();
}
public void SetValue(object targetResource, string propertyName, object propertyValue)
{
targetResource.GetType().GetProperty(propertyName).SetValue(targetResource, propertyValue, null);
}
}
}
Stack trace when breaking in IQueryable
> WebApplication5.DLL!Test.Provider.Employees.get() Line 24 C#
[Lightweight Function]
System.Data.Services.dll!System.Data.Services.Providers.ReflectionServiceProvider.GetResourceContainerInstance(System.Data.Services.Providers.ResourceSet resourceContainer) + 0x1ec bytes
System.Data.Services.dll!System.Data.Services.Providers.BaseServiceProvider.GetQueryRootForResourceSet(System.Data.Services.Providers.ResourceSet container) + 0xb bytes
System.Data.Services.dll!System.Data.Services.RequestUriProcessor.CreateFirstSegment(System.Data.Services.IDataService service, string identifier, bool checkRights, string queryPortion, bool isLastSegment, out bool crossReferencingUrl) + 0x40e bytes
System.Data.Services.dll!System.Data.Services.RequestUriProcessor.CreateSegments(string[] segments, System.Data.Services.IDataService service) + 0x103 bytes
System.Data.Services.dll!System.Data.Services.RequestUriProcessor.ProcessRequestUri(System.Uri absoluteRequestUri, System.Data.Services.IDataService service) + 0x3b bytes
System.Data.Services.dll!System.Data.Services.DataService<Test.Provider>.ProcessIncomingRequestUri() + 0xe2 bytes
System.Data.Services.dll!System.Data.Services.DataService<Test.Provider>.HandleRequest() + 0xc0 bytes
System.Data.Services.dll!System.Data.Services.DataService<Test.Provider>.ProcessRequestForMessage(System.IO.Stream messageBody) + 0x65 bytes
[Lightweight Function]
System.ServiceModel.dll!System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(object instance, object[] inputs, out object[] outputs) + 0x33f bytes
System.ServiceModel.dll!System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(ref System.ServiceModel.Dispatcher.MessageRpc rpc) + 0x137 bytes
System.ServiceModel.dll!System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(ref System.ServiceModel.Dispatcher.MessageRpc rpc) + 0x5e bytes
System.ServiceModel.dll!System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage41(ref System.ServiceModel.Dispatcher.MessageRpc rpc) + 0x6c bytes
System.ServiceModel.dll!System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage4(ref System.ServiceModel.Dispatcher.MessageRpc rpc) + 0x89 bytes
System.ServiceModel.dll!System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage31(ref System.ServiceModel.Dispatcher.MessageRpc rpc) + 0x59 bytes
System.ServiceModel.dll!System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage3(ref System.ServiceModel.Dispatcher.MessageRpc rpc) + 0x3b bytes
System.ServiceModel.dll!System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage2(ref System.ServiceModel.Dispatcher.MessageRpc rpc) + 0x4e bytes
System.ServiceModel.dll!System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage11(ref System.ServiceModel.Dispatcher.MessageRpc rpc) + 0x125 bytes
System.ServiceModel.dll!System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage1(ref System.ServiceModel.Dispatcher.MessageRpc rpc) + 0x34 bytes
System.ServiceModel.dll!System.ServiceModel.Dispatcher.MessageRpc.Process(bool isOperationContextSet) + 0xff bytes
System.ServiceModel.dll!System.ServiceModel.Dispatcher.ChannelHandler.DispatchAndReleasePump(System.ServiceModel.Channels.RequestContext request, bool cleanThread, System.ServiceModel.OperationContext currentOperationContext) + 0x44b bytes
System.ServiceModel.dll!System.ServiceModel.Dispatcher.ChannelHandler.HandleRequest(System.ServiceModel.Channels.RequestContext request, System.ServiceModel.OperationContext currentOperationContext) + 0x127 bytes
System.ServiceModel.dll!System.ServiceModel.Dispatcher.ChannelHandler.AsyncMessagePump(System.IAsyncResult result) + 0x43 bytes
System.ServiceModel.dll!System.ServiceModel.Dispatcher.ChannelHandler.OnAsyncReceiveComplete(System.IAsyncResult result) + 0x44 bytes
System.Runtime.DurableInstancing.dll!System.Runtime.Fx.AsyncThunk.UnhandledExceptionFrame(System.IAsyncResult result) + 0x32 bytes
System.Runtime.DurableInstancing.dll!System.Runtime.AsyncResult.Complete(bool completedSynchronously) + 0xfd bytes
System.Runtime.DurableInstancing.dll!System.Runtime.InputQueue<System.ServiceModel.Channels.RequestContext>.AsyncQueueReader.Set(System.Runtime.InputQueue<System.ServiceModel.Channels.RequestContext>.Item item) + 0x44 bytes
System.Runtime.DurableInstancing.dll!System.Runtime.InputQueue<System.ServiceModel.Channels.RequestContext>.EnqueueAndDispatch(System.Runtime.InputQueue<System.ServiceModel.Channels.RequestContext>.Item item, bool canDispatchOnThisThread) + 0x1aa bytes
System.Runtime.DurableInstancing.dll!System.Runtime.InputQueue<System.ServiceModel.Channels.RequestContext>.EnqueueAndDispatch(System.ServiceModel.Channels.RequestContext item, System.Action dequeuedCallback, bool canDispatchOnThisThread) + 0x5e bytes
System.ServiceModel.dll!System.ServiceModel.Channels.SingletonChannelAcceptor<System.ServiceModel.Channels.IReplyChannel,System.ServiceModel.Channels.ReplyChannel,System.ServiceModel.Channels.RequestContext>.Enqueue(System.ServiceModel.Channels.RequestContext item, System.Action dequeuedCallback, bool canDispatchOnThisThread) + 0x6b bytes
System.ServiceModel.dll!System.ServiceModel.Channels.HttpChannelListener.HttpContextReceived(System.ServiceModel.Channels.HttpRequestContext context, System.Action callback) + 0x1b4 bytes
System.ServiceModel.Activation.dll!System.ServiceModel.Activation.HostedHttpTransportManager.HttpContextReceived(System.ServiceModel.Activation.HostedHttpRequestAsyncResult result) + 0xd6 bytes
System.ServiceModel.Activation.dll!System.ServiceModel.Activation.HostedHttpRequestAsyncResult.HandleRequest() + 0x232 bytes
System.ServiceModel.Activation.dll!System.ServiceModel.Activation.HostedHttpRequestAsyncResult.BeginRequest() + 0x27 bytes
System.ServiceModel.Activation.dll!System.ServiceModel.Activation.HostedHttpRequestAsyncResult.OnBeginRequest(object state) + 0x49 bytes
System.ServiceModel.Activation.dll!System.ServiceModel.AspNetPartialTrustHelpers.PartialTrustInvoke(System.Threading.ContextCallback callback, object state) + 0x35 bytes
System.ServiceModel.Activation.dll!System.ServiceModel.Activation.HostedHttpRequestAsyncResult.OnBeginRequestWithFlow(object state) + 0x7a bytes
System.Runtime.DurableInstancing.dll!System.Runtime.IOThreadScheduler.ScheduledOverlapped.IOCallback(uint errorCode, uint numBytes, System.Threading.NativeOverlapped* nativeOverlapped) + 0x78 bytes
System.Runtime.DurableInstancing.dll!System.Runtime.Fx.IOCompletionThunk.UnhandledExceptionFrame(uint error, uint bytesRead, System.Threading.NativeOverlapped* nativeOverlapped) + 0x39 bytes
mscorlib.dll!System.Threading._IOCompletionCallback.PerformIOCompletionCallback(uint errorCode, uint numBytes, System.Threading.NativeOverlapped* pOVERLAP) + 0x74 bytes
[Native to Managed Transition]
[Appdomain Transition]
[Native to Managed Transition]
There are a couple of issues here:
We have a bug in WCF DS. It was tough to consider fixing this while we were in the .NET Framework because of the potential for breaking changes. Now that we are out of the Framework and we have a public ask, we should fix this.
We don't enumerate the IQueryable, which means that the QueryProvider will never actually execute the query. As long as the getter is just returning an IQueryable and not doing any work, we shouldn't see any more than a nominal performance hit from this.
All of that said, it is something we can and should fix so that we don't leave people wondering about it. We'll try to get a fix out in 5.0.2 or 5.1.0 if we have the bandwidth to do so.