Returning bitmap from restful web service - c#

Car.cs
[DataContract]
public class Car
{
[DataMember]
public string Id { get; set; }
[DataMember]
public Bitmap Image { get; set; }
}
ICarService.cs
[ServiceContract]
public interface ICarService
{
[OperationContract]
[WebGet(UriTemplate = "Car/{id}")]
Car GetCarId(string id);
}
CarService.svc.cs
public class CarService : ICarService
{
public Car GetCarId(string id)
{
var newCar = new Car
{
Id = id,
Image = new Bitmap("../../Atish.jpg")
};
return newCar;
}
}
web.config
<?xml version="1.0"?>
<configuration>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>
<system.web>
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5"/>
</system.web>
<system.serviceModel>
<services>
<service name="CarHaat.CarService">
<endpoint address="" behaviorConfiguration="restfulBehavior"
binding="webHttpBinding" bindingConfiguration="" contract="CarHaat.ICarService" />
<host>
<baseAddresses>
<add baseAddress="http://localhost/bookservice" />
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior name="restfulBehavior">
<webHttp />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
<protocolMapping>
<add binding="basicHttpsBinding" scheme="https" />
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<!--
To browse web app root directory during debugging, set the value below to true.
Set to false before deployment to avoid disclosing web app folder information.
-->
<directoryBrowse enabled="true"/>
</system.webServer>
</configuration>
Problem is .... when i hit this url localhost:4765/CarService.svc/car/1 in browser, I get following exception. How can i resolve it?? I want to return an image in json format.

what is the call stack trace? if I were you, I would go to the debug > Exception menu and then tick the "thrown" check box for the Common Language Runtime Exceptions item. This will then take you to exactly where the exception is being thrown from. To me, I believe it could be thrown from the Bitmap constructor as you are giving it an incorrect path. you need to map the path to the image file in question by using Server.MapPath for example. It needs a fully qualified path to the file in question when it comes to the web platform.
in addition to that, the file will be locked until you dispose of the bitmap object so you may have issues. The best thing to do is probably return the byte[] of the image file to the client and let the client side deal with streaming it to the page (for example using the response to write the bytes to the page). it also makes sense if you are using the WCF platform and making a form of an API system, where you are not tied to using the .NET BCL's but to make it as generic as possible that majority of not all of the clients understand the native types

Return the image Serialized in Base64 (string) and then in the client Deserialize it
Like this
//Serialize
var bytes = File.ReadAllBytes(#"bbbd996028159395cce9b63d717bf0ef.jpeg");
var base64 = Convert.ToBase64String(bytes);
//Deserialize
var nbytes = Convert.FromBase64String(base64);
File.WriteAllBytes(#"yayaya.jpeg", nbytes);

Related

WCF rest WebInvoke get method not working returning 404 error

I created a basic WCF REST service with default methods.
It is working when i request for svc file, but it returns 404 error while placing a request with rest parameters.
i.e. it gives response when i call http://localhost/FirstWCFRestApp/RestServiceImpl.svc but returns 404 error when i called http://localhost/FirstWCFRestApp/RestServiceImpl.svc/xml/12.
It is very basic service with only 1 method and confusing me as why its not working.
I have pasted the code below.
Please let me know where it went wrong and why its not working.
Interface`
using System.ServiceModel;
using System.ServiceModel.Web;
namespace FirstWCFRestApp
{
// NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface name "IRestServiceImpl" in both code and config file together.
[ServiceContract]
public interface IRestServiceImpl
{
[OperationContract]
[WebInvoke(Method="Get",UriTemplate="/xml/{id}",RequestFormat=WebMessageFormat.Json,
ResponseFormat=WebMessageFormat.Json)]
string DoWork(string id);
}
}
Class File`
namespace FirstWCFRestApp
{
// NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "RestServiceImpl" in code, svc and config file together.
// NOTE: In order to launch WCF Test Client for testing this service, please select RestServiceImpl.svc or RestServiceImpl.svc.cs at the Solution Explorer and start debugging.
public class RestServiceImpl : IRestServiceImpl
{
public string DoWork(string id)
{
return "You requested Id is "+ id;
}
}
}
SVC file
<%# ServiceHost Language="C#" Debug="true" Service="FirstWCFRestApp.RestServiceImpl" CodeBehind="RestServiceImpl.svc.cs" %>
Web.Config
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5"/>
</system.web>
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"
multipleSiteBindingsEnabled="true" />
<behaviors>
<endpointBehaviors>
<behavior name="FWRBehaviour">
<webHttp/>
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="htBehaviour">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service name="FirstWCFRestApp.RestServiceImpl" behaviorConfiguration="htBehaviour">
<endpoint address="Stud" binding="webHttpBinding"
contract="FirstWCFRestApp.IRestServiceImpl" behaviorConfiguration="FWRBehaviour"></endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"></endpoint>
</service>
</services>
</system.serviceModel>
<system.webServer>
<directoryBrowse enabled="true"/>
</system.webServer>
</configuration>
The address http://localhost/FirstWCFRestApp/RestServiceImpl.svc is the service metadata address.
The practical service address should base on the UriTemplate property and the Address property of the service address.
UriTemplate="/xml/{id}"
binding="webHttpBinding"
contract="FirstWCFRestApp.IRestServiceImpl" >behaviorConfiguration="FWRBehaviour">
In addition, the Method property of the WebInvoke should be capitalized.
[WebInvoke(Method ="GET",ResponseFormat =WebMessageFormat.Json,UriTemplate ="/xml/{id}")]
In summary, the service address should be,
http://localhost/FirstWCFRestApp/RestServiceImpl.svc/Stud/xml/12
Feel free to let me know if there is anything I can help with.
Like Abraham said:
Web Invoke Format:{SVC Path}/{webHttpBinding Endpoint Address}/{WebInvoke UriTemplate}
In your case, it should be:
http://localhost/FirstWCFRestApp/RestServiceImpl.svc/Stud/xml/12

WCF REST GET returns "Endpoint not found"

So I am trying to create a very basic WCF service with REST GET but there is only "Endpoint not found". I am sending GET via Postman App to address:
http://localhost:8733/Design_Time_Addresses/RESTfulTest/Service1/json
Service is hosted by IIS; Here's all my code:
namespace RESTfulTest
{
[ServiceContract]
public interface IService1
{
[OperationContract]
[WebGet]
string GetText();
}
}
namespace RESTfulTest
{
[ServiceBehavior(InstanceContextMode =InstanceContextMode.Single)]
public class Service1 : IService1
{
public string GetText()
{
return "Hello REST";
}
}
}
And App.config file:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>
<system.web>
<compilation debug="true" />
</system.web>
<system.serviceModel>
<services>
<service name="RESTfulTest.Service1">
<host>
<baseAddresses>
<add baseAddress = "http://localhost:8733/Design_Time_Addresses/RESTfulTest/Service1/" />
</baseAddresses>
</host>
<endpoint address="json" binding="webHttpBinding" behaviorConfiguration="jsonBehavior" contract="RESTfulTest.IService1"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="True" httpsGetEnabled="True"/>
<serviceDebug includeExceptionDetailInFaults="False" />
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="jsonBehavior">
<enableWebScript/>
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
What am I missing here?
Are you going to be using ASP.NET Ajax to call the service? If not, you should not be using the <enableWebScript> behavior, but rather the <webHttp> behavior.
Also, you should probably remove the <serviceMetadata> behavior, since you won't be exposing WSDL from your service.
So everything was set up properly. The endpoint address that I was asking was incorrect. It should be http://localhost:8733/Design_Time_Addresses/RESTfulTest/Service1/json/GetText
I didn't know that function name should be added to the address, that's the point.

WCF WebFaultException details not sent to client

Ok, so..
I have a WCF service that throws a WebFaultException<Error>(Error, HttpStatusCode.BadRequest) where Error is my custom, serializable object.
This all works as expected when I host the service on my local machine, and on GoDaddy's (as seen here: link removed).
But when hosted with Arvixe all I receive is a 'Bad Request' response (as seen here: link removed)
Analyzing the response headers, it appears that my local machine, GoDaddy, and Arvixe are all using the same .NET version. However, my local machine is running IIS 8.0, GoDaddy is running IIS 7.0, and Arvixe is running IIS 8.5.
So, what's causing the discrepancy? Does IIS 8.5 handle WebFaultException's differently? Nothing I find on the internet suggests it does. Or does IIS need to be configured to return WebFaultExceptions? Again, everything I read says it is configured entirely in the ASP Web.config.
Any other suggestions?
** EDIT **
I'm fairly certain this has to do with IIS and not my code, considering it works fine on my local machine (IIS8) and GoDaddy (IIS7), but not on Arvixe (IIS8.5)
Anyways, here's some snippets:
The error object I'm trying to return
[DataContract]
public class Error {
[DataMember]
public int Code { get; set; }
[DataMember]
public string Message { get; set; }
[DataMember]
public string Display { get; set; }
[DataMember]
public List<Error> Details { get; set; }
public Error(int code, string message, List<Error> details = null, string display = null) {
this.Code = code;
this.Message = message;
this.Display = display;
this.Details = details ?? new List<Error>();
}
}
Trying to return it to the client via:
throw new WebFaultException<Error>(new Error(802, "games/asdf"), HttpStatusCode.BadRequest);
The method I am trying to throw the WebFaultException from:
[OperationContract]
[WebInvoke(
Method = "GET",
UriTemplate = "/games/{game}/scores"
)]
List<Score> GetScores(string game);
I have tried adding a [FaultContract(typeof(Error))] attribute to the method but it had no effect.
Here's the Web.config registering my service
<?xml version="1.0"?>
<configuration>
<appSettings>
</appSettings>
<connectionStrings>
<!-- DEV -->
<add name="App" connectionString="XXX" />
<add name="Log" connectionString="XXX" />
</connectionStrings>
<system.web>
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5" />
<webServices>
<protocols>
<clear />
<add name="HttpGet"/>
<add name="HttpPost" />
<add name="HttpPostLocalhost" />
</protocols>
</webServices>
<pages>
<namespaces>
<add namespace="System.Web.Optimization" />
</namespaces>
</pages>
</system.web>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<!--old-->
<behavior name="OldService">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
<!--new-->
<behavior name="V3">
<serviceAuthorization serviceAuthorizationManagerType="ScoresWs.V3.Auth, ScoresWs"/>
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="REST">
<!--faultExceptionEnabled needs to be false or else we return .net exceptions as xml instead of our custom WebFaultException-->
<webHttp
helpEnabled="true"
faultExceptionEnabled="false"
automaticFormatSelectionEnabled="false"
defaultOutgoingResponseFormat="Json" />
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<webHttpBinding>
<binding name="defaultBinding" maxReceivedMessageSize="2097152">
<security mode="None" />
</binding>
</webHttpBinding>
</bindings>
<services>
<service name="ScoresWs.WebServiceV2" behaviorConfiguration="OldService">
<endpoint
address=""
binding="webHttpBinding"
behaviorConfiguration="REST"
bindingConfiguration="defaultBinding"
contract="ScoresWs.IWebServiceV2" />
</service>
<service name="ScoresWs.V3.Api" behaviorConfiguration="V3">
<endpoint
address=""
binding="webHttpBinding"
behaviorConfiguration="REST"
bindingConfiguration="defaultBinding"
contract="ScoresWs.V3.IApi"/>
</service>
</services>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true" />
<directoryBrowse enabled="false" />
</system.webServer>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="WebGrease" publicKeyToken="31ad335" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-1.5.2.14234" newVersion="1.5.2.14234" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
Annnnnnd lastly I activate the webservices in my Global.asax:
public class Global : System.Web.HttpApplication {
protected void Application_Start(object sender, EventArgs e) {
RouteTable.Routes.Add(new ServiceRoute("api/v2", new WebServiceHostFactory(), typeof(ScoresWs.WebServiceV2)));
RouteTable.Routes.Add(new ServiceRoute("api/v3", new WebServiceHostFactory(), typeof(ScoresWs.V3.Api)));
}
}
Solved it! Like I suspected, it had nothing to do with my code.
In the Arvixe hosting panel I had to enabled "Show detailed ASP.NET errors in browser" (WebSites->Errors->ASP.NET). However, I'm not exactly sure what impact this has on security, since the Web.config hasn't changed and I can't see the IIS configuration.
Odd that the Arvixe support team wouldn't have directed me here immediately considering 'my detailed ASP.NET errors' weren't being sent to the client.

WCF recieves a complex object as null

After getting input in another thread here on the forum [StackOverFlow][1]
[1]: Getting a nullreference when passing a complex object from KSOAP2 to WCF have i reached conclusion that my problem is with the WCF service itself. It seems that the service is not able to understand the object that it's receiving.
No matter what I do the object passed is always null.
I have even tried declaring the datamember explicit even though it should not be necessary in the current version of WCF.
Here's the class I'm trying to pass through the WCF:
namespace ModelLayer
{
[DataContract]
public class User
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string UserName { get; set; }
[DataMember]
public string Mac { get; set; }
public User()
{
}
}
}
My service interface:
[ServiceContract (Namespace = "http://nordahl.org/")]
public interface IWcfFoodAndAllergi
{
[OperationContract]
int InsertUser(User _user);
[OperationContract]
User GetUser(string _mac);
[OperationContract]
int InsertRecipe(Recipe _recipe);
[OperationContract]
List<Recipe> GetRecipeByAllergi(List<Allergies> _allergies);
[OperationContract]
List<Recipe> GetRecipeByType(string _type);
[OperationContract]
List<Recipe> GetRecipeByName(string _name);
}
}
And lastly the webconfig file itself:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>
<system.web>
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5" maxRequestLength="1048576"/>
</system.web>
<system.webServer>
<security>
<requestFiltering>
<requestLimits maxAllowedContentLength="1073741824" />
<fileExtensions allowUnlisted="true">
<remove fileExtension=".cs"/>
<add fileExtension=".cs" allowed="true"/>
</fileExtensions>
</requestFiltering>
</security>
</system.webServer>
<system.serviceModel>
<services>
<service name="WcfFoodAndAllergi.WcfFoodAndAllergi">
<!-- Use a bindingNamespace to eliminate tempuri.org -->
<endpoint address=""
binding ="basicHttpBinding"
bindingNamespace="http://nordahl.org/"
contract="WcfFoodAndAllergi.IWcfFoodAndAllergi"
/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name ="">
<!-- To avoid disclosing metadata information, set the values below to false before deployment -->
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<protocolMapping>
<add binding="basicHttpsBinding" scheme="https" />
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<!--
To browse web app root directory during debugging, set the value below to true.
Set to false before deployment to avoid disclosing web app folder information.
-->
<directoryBrowse enabled="true"/>
</system.webServer>
</configuration>
I had a similar problem to yours when a complex object referenced another complex object in a T4 generated class. If you are using an include in an obtain method, or another method relating to Entity or objects linking complex objects to each other; you may get a circular reference error. I had a friend show me how to fix this with a custom class that sets up an attribute:
Complex Object won't return when using 'include' syntax in WCF with Entity Version 6

WCF JSON data not showing in browser

Was trying alot and brows-ing around but I fail to figure out what is wrong with my WCF service.
What I am trying to acchive:
I am builindg a WCF that would expose some data as a json structure over HTTP
I will evenutally use that in an andorid app to show the data.
The mockup:
1.) The interface:
namespace WcfSyncDBService
{
// NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface name "ISyncDBService" in both code and config file together.
[ServiceContract]
public interface ISyncDBService
{
[OperationContract]
[WebInvoke(Method = "GET", BodyStyle = WebMessageBodyStyle.Wrapped,
ResponseFormat = WebMessageFormat.Json, UriTemplate = "GetTodoItems")]
TodoItem[] GetTodoItems();
}
[DataContract(Name = "TodoItems")]
public class TodoItem
{
[DataMember(Name = "Id")]
public int Id { get; set;}
[DataMember(Name = "Category")]
public string Category { get; set; }
[DataMember(Name = "Summary")]
public string Summary { get; set; }
[DataMember(Name = "Description")]
public string Description { get; set; }
}
}
2.) The Service:
namespace WcfSyncDBService
{
// NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "SyncDBService" in code, svc and config file together.
public class SyncDBService : ISyncDBService
{
public TodoItem[] GetTodoItems()
{
var context = new SyncDBEntities();
var query = from i in context.todo select i;
var itemList = query.ToList();
List<TodoItem> todoList = new List<TodoItem>();
foreach (var item in itemList)
{
TodoItem i = new TodoItem
{
Id = item.C_id,
Category = item.category,
Summary = item.summary,
Description = item.description
};
todoList.Add(i);
}
return todoList.ToArray();
}
}
}
3.) Web config:
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<services>
<service name="WcfSyncDBService.SyncDBService">
<!-- Service Endpoints -->
<!-- Unless fully qualified, address is relative to base address supplied above -->
<endpoint address="" binding="webHttpBinding" contract="WcfSyncDBService.ISyncDBService" behaviorConfiguration="web" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="true"/>
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="web">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
<connectionStrings>
<add name="SyncDBEntities" connectionString="metadata=res://*/SyncDBmodel.csdl|res://*/SyncDBmodel.ssdl|res://*/SyncDBmodel.msl;provider=System.Data.SqlClient;provider connection string="data source=.;initial catalog=SyncDB;integrated security=True;multipleactiveresultsets=True;App=EntityFramework"" providerName="System.Data.EntityClient" />
</connectionStrings>
</configuration>
When I run the service I get the definition and the wsdl:
http://localhost:18131/SyncDBService.svc
But when I try to call the function http://localhost:18131/SyncDBService.svc/GetTodoItems/ I get an error "Endpoint not found."
I know the error is probably in the web.config but I simply fail to find it hope someone can help me out.
EDIT1: (web.config after Siva's sugesstion)
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<services>
<service name="WcfSyncDBService.SyncDBService">
<!-- Service Endpoints -->
<!-- Unless fully qualified, address is relative to base address supplied above -->
<endpoint address="" binding="webHttpBinding" contract="WcfSyncDBService.ISyncDBService" behaviorConfiguration="web" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="true"/>
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="web">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true">
<serviceActivations>
<add relativeAddress="SyncDBService.svc" service="WcfSyncDBService.SyncDBService" />
</serviceActivations>
</serviceHostingEnvironment>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
<connectionStrings>
<add name="SyncDBEntities" connectionString="metadata=res://*/SyncDBmodel.csdl|res://*/SyncDBmodel.ssdl|res://*/SyncDBmodel.msl;provider=System.Data.SqlClient;provider connection string="data source=.;initial catalog=SyncDB;integrated security=True;multipleactiveresultsets=True;App=EntityFramework"" providerName="System.Data.EntityClient" />
</connectionStrings>
</configuration>
You need to configure relative address on service host,
<serviceHostingEnvironment multipleSiteBindingsEnabled="true">
<serviceActivations>
<add relativeAddress="SyncDBService.svc" service="WcfSyncDBService.SyncDBService" />
</serviceActivations>
</serviceHostingEnvironment>

Categories

Resources