Why do I got warning "CodeContracts: Possibly calling a method on a null reference 'stream'." on this code sample?
public static void Test()
{
var request = (HttpWebRequest)HttpWebRequest.Create("some url");
Contract.Assume(request != null);
var stream = request.GetRequestStream();
stream.Flush(); // WARNING IN THIS LINE
}
I am asking because I use Reflector at System.Contracts.dll and there is next line in GetRequestStream() method of HttpWebRequest class:
public virtual Stream GetRequestStream()
{
Contract.Ensures(Contract.Result<Stream>() != null, null, "Contract.Result<System.IO.Stream>() != null");
}
That contract is ignored because there is no method to which it applies. There is no public virtual Stream GetRequestStream in HttpWebRequest. There is, however, a public virtual Stream GetRequestStream in WebRequest, and there is a public override Stream GetRequestStream in HttpWebRequest, but neither of those have any contracts in System.Contracts.dll.
You can report it as a bug, and you can use Contract.Assume to avoid the warning.
Related
One parameter in a Web API method is unexpectedly null, so I want to inspect the request. In support of this I wrote an ActionFilterAttribute and implemented the OnActionExecuting method. Attempting to retrieve Content as per the code below returns an empty string, but ContentLength says content is 345 bytes and content type is JSON (as expected).
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Http.Controllers;
using System.Web.Http.Filters;
namespace Website.ActionFilters
{
public class ActionFilterSniffAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
Task<string> task = actionContext.Request.Content.ReadAsStringAsync();
while (task.Status != TaskStatus.RanToCompletion)
Thread.Sleep(10);
Debug.WriteLine(task.Result);
}
}
}
What is the correct way to get hold of the HTTP request string? Installing Fiddler on the server is not something I'm keen to do.
This mechanism worked for me and is a good explanation of what is occurring.
Web API action filter content can't be read
public override async void OnActionExecuting(HttpActionContext actionContext)
{
System.Net.Http.HttpRequestMessage request = actionContext.Request;
Stream reqStream = await request.Content.ReadAsStreamAsync();
if (reqStream.CanSeek)
{
reqStream.Position = 0;
}
//now try to read the content as string
string data = await request.Content.ReadAsStringAsync();
Debugger.Break();
}
I have working WCF REST web service and can set status codes and status descriptions as usual:
OutgoingWebResponseContext response = WebOperationContext.Current.OutgoingResponse;
response.StatusCode = statusCode;
response.StatusDescription = detail.Error;
But I want to use WebFaultException. Unfortunately it alvays return {"Detail":"Not Found"} when I run my code:
[Serializable]
[DataContract]
public class DtoError
{
public DtoError()
{
}
public DtoError(string error)
{
Error = error;
}
[DataMember]
public string Error { get; private set; }
}
var error = new DtoError(entityName + " is not existing");
throw new WebFaultException<DtoError>(error, HttpStatusCode.NotFound);
Can I return my custom error json object?
After investigation I found that instead of WebServiceHost we are using WebServiceHost2 from Rest Starter Kit. And inside that host we have to use WebProtocolException. So now my working code looks like that:
throw new WebProtocolException(HttpStatusCode.NotFound, "Not Found", error, null);
Server side interface:
[OperationContract]
[WebGet(UriTemplate = "GetCardInfoByCardNumber/?cardNumber={cardNumber}&SerialNumber={SerialNumber}&token={token}", ResponseFormat = WebMessageFormat.Json)]
IList<Cards> GetCardInfoByCardNumber(string cardNumber, string SerialNumber, string token);
Server side implementation:
public IList<Cards> GetCardInfoByCardNumber(string cardNumber, string SerialNumber, string token)
{
if (BaseClass.HasPermission(token))
return cm.GetCardInfoByCardNumber(cardNumber, SerialNumber);
else
return null;
}
Client side:
class Program
{
static void Main(string[] args)
{
TestResWCF();
Console.ReadLine();
}
static List<Cards> TestResWCF()
{
List<Cards> a = null;
string ServiceUri = "http://192.168.15.18:8089/GetCardInfoByCardNumber/?cardNumber=HH-120109-017&SerialNumber=&token=123456";
WebClient proxy = new WebClient();
proxy.Encoding = Encoding.UTF8;
proxy.DownloadStringCompleted += new DownloadStringCompletedEventHandler
(
(s, e) =>
{
Stream stream = new MemoryStream(Encoding.Unicode.GetBytes(e.Result));
DataContractJsonSerializer obj = new DataContractJsonSerializer(typeof(List<Cards>));
a = obj.ReadObject(stream) as List<Cards>;
}
);
proxy.DownloadStringAsync(new Uri(ServiceUri));
return a;
}
List<Cards> a return empty string always! How to return data? Thank you very much!
Do you have any example? sorry for my bad english
Can you share the code for the "Cards" and "Card" classes?
I'm very sure that most likely, it is not decorated with [DataContract] and [DataMember] properly. You may have decorated the type with [DataContract], but forgotten to annotate the members you want with [DataMember]. Or alternatively, you may not have decorated them at all, and something else is happening behind the scenes. In 99% of the scenarios, misdecoration or improper decoration or mis-initialization of the serializer is the reason this error occurs.
If you did decorate it properly, there may be some other problems. It's hard to tell with 100% certainty from just the detail you've provided, so I'd enable tracing to generate tracing logs (that you can then view/share with SvcTraceViewer) and turn on debug exceptions (by turning on the includeExceptionDetailInFaults setting).
Consider the following very basic WCF service implementation:
public enum TransactionStatus
{
Success = 0,
Error = 1
}
public class TransactionResponse
{
public TransactionStatus Status { get; set; }
public string Message { get; set; }
}
[ServiceContract]
[XmlSerializerFormat]
public interface ITestService
{
[OperationContract]
TransactionResponse DoSomething(string data);
}
public class TestService : ITestService
{
public TransactionResponse DoSomething(string data)
{
var result = ProcessData(data); // may throw InvalidOperationException
return new TransactionResponse()
{
Status = TransactionStatus.Success,
Message = result
};
}
private string ProcessData(string data)
{
if (data = "foobar")
throw new InvalidOperationException();
return data;
}
}
In the instance that the DoSomething method does throw an InvalidOperationException, I would like to intercept the fault and return a TransactionResponse object, rather than have WCF raise a FaultException with the client. How can I do this without surrounding each method body in a huge try catch statement? Is there some where I can hook into? Can I do this with some sort of attribute or something? An example of how I would like to handle it can be demonstrated using ASP.NET MVC:
public class ApiController : BaseController
{
protected override void OnException(ExceptionContext filterContext)
{
var ex = filterContext.Exception;
var message = HttpContext.IsDebuggingEnabled ? ex.ToString() : ex.Message;
_logger.Error("Error processing request for controller {0}, action {1}",
filterContext.RequestContext.RouteData.Values["controller"],
filterContext.RequestContext.RouteData.Values["action"]);
_logger.Error(ex.ToString());
filterContext.ExceptionHandled = true;
filterContext.Result = ToXml(new ApiResult(false)
{
Message = message
});
}
// ...
}
Using the above method in MVC, I can ensure that no matter which controller action throws an exception, I can handle it and return an appropriately formatted ActionResult containing the necessary info. Is there a way to do this kind of thing with WCF?
Check out the WCF IErrorHandler interface - it allows you to centrally define one way in your service implementation to catch all exceptions and either swallow them, or convert them to WCF-friendly SOAP exceptions. This will make sure the channel between the client and the server isn't faulted, e.g. it can still be used after this call failed.
I don't understand why you'd want to "catch" the SOAP faults and convert those to something else, though.... nor do I know of any support that WCF would give you. The basic assumption is: catch .NET exceptions and convert them into interoperable SOAP faults
So here's a super simple interface for doing rest in WCF.
[ServiceContract]
public interface IRestTest
{
[OperationContract]
[WebGet(UriTemplate="Operation/{value}")]
System.IO.Stream Operation(string value);
}
It works great, until i try to pass a string with periods in it, such as a DNS name... I get a 404 out of asp.net.
Changing the UriTemplate to stick parameters into the query string makes the problem go away. Anyone else see this or have a workaround?
That is true that a path part cannot contain a period or many other special characters for that matter. I experienced the same problem a while back and received an answer from TechNet team stating that querystring is your only option the could find. Sorry
http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/d03c8331-1e98-4d5d-82a7-390942a93012/
I have a service with almost the exact signature. I can pass values that have a "." in the name. For example, this would work on mine:
[OperationContract]
[WebGet(UriTemplate = "category/{id}")]
string category(string id);
with the url http://localhost/MyService.svc/category/test.category I get the value `"test.category" passed in as the string value.
So there must be some other issue. how are you accessing the URL? just directly in the browser? Or via a javascript call? Just wondering if it is some error on the client side. The server passes the value just fine. I would recommending trying to access the url in your browser, and if it doesn't work then post exactly what URL you are using and what the error message was.
Also, are you using WCF 3.5 SP1 or just WCF 3.5? In the RESTFul .Net book I'm reading, I see there were some changes with regards to the UriTemplate.
And finally, I modified a simple Service from the RESTFul .Net book that works and I get the correct response.
class Program
{
static void Main(string[] args)
{
var binding = new WebHttpBinding();
var sh = new WebServiceHost(typeof(TestService));
sh.AddServiceEndpoint(typeof(TestService),
binding,
"http://localhost:8889/TestHttp");
sh.Open();
Console.WriteLine("Simple HTTP Service Listening");
Console.WriteLine("Press enter to stop service");
Console.ReadLine();
}
}
[ServiceContract]
public class TestService
{
[OperationContract]
[WebGet(UriTemplate = "category/{id}")]
public string category(string id)
{
return "got '" + id + "'";
}
}
Here's an example HttpModule that fixes the 'period' when they occur in REST parameters. Note that I've only seen this happen in the Development Server (aka Cassini), in IIS7 it seems to work without this "hack". The example I've included below also replaces the file extension '.svc' which I adapted from this answer. How to remove thie “.svc” extension in RESTful WCF service?
public class RestModule : IHttpModule
{
public void Dispose()
{
}
public void Init(HttpApplication context)
{
context.BeginRequest +=
delegate
{
HttpContext ctx = HttpContext.Current;
string path = ctx.Request.AppRelativeCurrentExecutionFilePath;
int i = path.IndexOf('/', 2);
if (i > 0)
{
int j = path.IndexOf(".svc", 2);
if (j < 0)
{
RewritePath(ctx, path, i, ".svc");
}
else
{
RewritePath(ctx, path, j + 4, "");
}
}
};
}
private void RewritePath(HttpContext ctx, string path, int index, string suffix)
{
string svc = path.Substring(0, index) + suffix;
string rest = path.Substring(index);
if (!rest.EndsWith(ctx.Request.PathInfo))
{
rest += ctx.Request.PathInfo;
}
string qs = ctx.Request.QueryString.ToString();
ctx.RewritePath(svc, rest, qs, false);
}
}