So I have a function which returns a pdf stream. The calling procedure gets the stream and writes it to disk (thanks ServiceGuy!). Normal VB code is as follows:
Public Function GetPDF() As System.IO.FileStream
GetPDF = File.OpenRead("C:\Documents and Settings\jspel903\Desktop\3211LD.pdf")
End Function
Now, for whatever reason when I put that code in my WCF (see below) and build/install, it won't return anything. The calling procedure gets nothing after My WCF is hosted in a Windows service (I can't get it to debug or step into). So I'm wondering if, perhaps, WCFs won't return a FileStream?
Here's the IService:
<ServiceContract()> _
Public Interface IService1
<OperationContract()> _
Function GetPDF() As System.IO.FileStream
'Should return a .pdf file as a stream
End Interface
Here's the svc:
Imports System.IO
Public Class Service1
Implements IService1
Public Function GetPDF() As System.IO.FileStream Implements IService1.GetPDF
GetPDF = File.OpenRead("C:\Documents and Settings\jspel903\Desktop\3211LD.pdf")
End Function
End Class
Seems to me like it should work. Any ideas?
You probably want to convert your FileStream to a byte array and return that. WCF is generally limited to returning serializable types.
// fs is your FileStream
byte[] Data = new byte[fs.Length];
fs.Read(Data,0,fs.Length);
It's not going to work... Think about what it would mean if it did. Your WCF client would have access to a file stream on your server device. It'd have to be able to perform all of the operations that you could do locally, over a remote connection.
WCF is a transport mechanism for data, it doesn't actually send object references to the server's objects. The client gets a copy of the object, that has been serialized by the server, then deserialized at the client side. If you could send a stream object, the file handle / memory reference etc wouldn't mean anything to the receiving client.
You need to read the data from the stream on the server and then convert it into an appropriate data object to transmit back to the client.
EDIT:
Apparently you can use streaming with WCF, but you're not going to be able to return a System.IO.FileStream, you can return a Stream.
Take a look at: Large Data And Streaming for a description and some of the restriction's you'll need to be aware of if you take that approach.
Related
In my WCF service, I am retrieving data from SQL server using Command.ExecuteReader() method. The data size is very large (around 1+ GB) and transferring this data to client over netTcp binding.
I am planning to implement stream mode instead of buffered mode in WCF. Can anyone point me to any article or document to do the same.
In simple words, my objective is to convert IDataReader to stream object that will transfer to client and client side, want to convert this stream back to dataset/datatable or anything that can be bind with Grid.
I cannot convert IdataReader to IEnumerable as data is coming through SP and no of columns in output set keep changing (I don;t want to add no of column limitation in code).
Ultimately, final communication will be done on dataset from WCF service to client app. If any solution like converting Dataset to stream, sent it to client and at client, convert stream back to dataset will also solve my problem.
You should not try to convert the IDataReader to a stream, but let your data access method return an IEnumerable of a type representing a single row of the query result like this:
public IEnumerable<Order> GetOrders()
{
IDbCommand cmd = ... <<build your command here>> ...
using(var rdr = cmd.ExecuteDataReader())
{
while(rdr.Read())
{
Order order = new Order {Id=rdr.GetDecimal(1), Name=rdr.GetString(2)};
yield return order;
}
}
}
Next you can serialize the result of this method to a stream (as shown by #Mohamed, for example). This way you can send a list of objects to the client without needing the complete resultset to be loaded in memory. And you are still sure the datareader is disposed when the reader has reached the end of the result.
you can convert anything to stream like this:
var stream = new MemoryStream(Encoding.UTF8.GetBytes(Newtonsoft.Json.JsonConvert.SerializeObject(datareader)));
but its not a best practice. you should create an array of objects with your datareader and then return it.
I'm new to serialization concept, please help in understanding concept.
What exactly serialization means? I have read the definition, but could not understand in details.
How basic types (int, string) are serialized?
If we don't use serialization in our code how data will be transmitted?
Is there any implicit serialization process involved while accessing database from front end Java/C# code? example insert/delete from database.
Serialization just takes an object and translates it into something simpler. Imagine that you had an object in C# like so:
class Employee
{
public int age;
public string fullname;
}
public static void Main()
{
var john = new Employee();
john.age = 21;
john.fullname = "John Smith";
var matt = new Employee();
matt.age = 44;
matt.fullname = "Matt Rogers";
...
This is C# friendly. But if you wanted to save that information in a text file in CSV format, you would end up with something like this:
age,fullname
21,John Smith
44,Matt Rogers
When you write a CSV, you are basically serializing information into a different format - in this case a CSV file. You can serialize your object to XML, JSON, database table(s), memory or something else. Here's an example from Udemy regarding serialization.
If you don't serialize, confusion will be transmitted. Perhaps your object's ToString() will be implictly called before transmission and whatever result gets transmitted. Therefore it is vital to convert your data to something that is receiver friendly.
There's always some serialization happening. When you execute a query that populates a DataTable, for example, serialization occurred.
Concept :
Serialization is the process of converting an object into series of bytes.
Usually the objects we use in application will be complex and all of them can be easily represented in the form of series of bytes which can be stored in the file/database or transfered over network.
You can make a class Serializable just by making it implement Serializable interface.
For a class to be serialized successfully, two conditions must be met:
The class must implement the java.io.Serializable interface.
All of the fields in the class must be serializable. If a field is not serializable, it must be marked transient.
When the program is done serializing, and if it is stored in a file with extension .ser then it can be used for deserializing.
Serialization gives an serialVersionUID to the serialized object which has to match for deserialization
I'm just looking for some general advice with this one please. My WCF WebMethod needs to work across applications using different software, e.g. ASP.NET --> Java, for example.
I know that in the event of a method failing, I can utilize FaultException(Of MyError) to generate a SOAP Fault, however, what is generally the best way to send a success message?
Take for example the following interface that defines functionality for saving a user into a database:
<ServiceContract()>
Public Interface IService1
<OperationContract()>
Sub SaveUserIntoDataBase(ByVal u As MyAppUser)
End Interface
<DataContract()>
Public Class MyAppUser
<DataMember()>
Public Property FirstName() As String
<DataMember()>
Public Property Surname() As String
End Class
If I needed to send feedback that the user was saved successfully, how would this be generally done? Is there a 'success' equivalent of a FaultException, or is it recommended to just return Boolean or a String?
I suppose a value should always be returned?
There isn't any equivalent success result to exception if execution of service call doesn't fail.
One option is to create some customzed types such as enums and return those based upon different results from underlying source.
The return types of every call may be different or customized to user needs. Returning a boolean value is better than some string value in your case. Also you are using a "Sub", so if its a function then this could be one case.
You can follow some discussion here as well:
Whats the best practice for returning a Boolean and string value
There is no need for a success message. If the operation did not fail, then it was a success.
Use a FaultException to indicate failure.
I have an ASP application, which calls an HTTP WCF service, which calls a TCP WCF service (all on different servers). I'm ultimately trying to pass one class object between the three.
I've discovered that I can't do this directly in the HTTP WCF, even though my class object is defined identically in BOTH WCFs. Like this:
Public Function CallOtherFunction(ByVal ThisClass as MyClass)
Dim RetVal as Boolean
RetVal = CallMyOtherWCFFunction(ThisClass)
End Function
Instead I have to:
Public Function CallOtherFunction(ByVal ThisClass as MyClass)
Dim RetVal as Boolean
Dim MyOutgoingClass as MyOtherWCF.MyClass
MyOutgoingClass.MyString = ThisClass.MyString
RetVal = CallMyOtherWCFFunction(MyOutgoingClass)
End Function
My objects are rather large, to say they have a lot of properties. Any way to not have to declare a new variable in my calling function, so my code can be a little easier (like the first example)?
Thanks,
Jason
You can't pass it directly because those are two diffrent types. You can, however, declare your data contracts in a shared assembly (used by the three projects, or at least by the HTTP and the TCP services), an when adding the service reference to create the proxy in the HTTP service, you specify that you want to "reuse types in referenced assemblies". This way it should use the same type in all projects.
Hey, I can't seem to access the returned value from a method I called on my Host.
//Service---------------------------------------------------------
[DataMember]
private List<CalculationRecord> History = new List<CalculationRecord>();
public IEnumerable<CalculationRecord> CalculationHistory()
{
return (IEnumerable<CalculationRecord>)History;
}
public CalculationResult Calculate(CalculationNode problem)
{
CalculationResult calcResult = new CalculationResult();
//Calculates results of expression
CalculationEvaluation Evaluator = new CalculationEvaluation();
Evaluator.Calculate(problem, calcResult);
return calcResult;
}
//interface---------------------------------------------------------
[ServiceContract]
public interface ICalculate
{
[OperationContract]
CalculationResult Calculate(CalculationNode problem);
[OperationContract]
IEnumerable<CalculationRecord> CalculationHistory();
}
//Client------------------------------------------------------------
CalculatorClient client = new CalculatorClient();
ICalculate calcProxy = client.ChannelFactory.CreateChannel();
CalculationNode calcRootNode = parser.Parse(expression);
CalculationResult result = calcProxy.Calculate(calcRootNode);//result is null
You're under a wrong impression - the DataContract that the server exposes can (and should) only contain data - never any behavior. As such, you can never share an object between client and host - all you can share are service methods to call, and concrete types to use on those methods. That's it.
The process is this: when the client connects up to the server, it will download the metadata for the service - it can find out what service methods are available, what data those take - but it cannot infer any additional methods on the data contract. It just can't. The client then builds up an exact copy of the data contract type - but it's a totally separate class, and it only matches the server-side data contract class as far as its serialized representation in XML is concerned. It is not the same class - it just look the same.
Because in the end, all that happens between the server and the client is an exchange of a serialized message - basically a XML text document. You are not sending across a .NET object! All you're exchanging is a data representation of your data contract, nothing more.
So in your case, the client side proxy will have a new class that looks like the one the server uses - at least on the serialized level on the wire - but it will not contain the Calculate method. The Calculate method you're calling is on the service contract - it's not the one on the data member you have.
In your concrete example, too - you seem to be intermixing [DataMember] and service interface definition. Avoid this at all costs. Also, all the types involved in the calculation - most definitely CalculationNode and CalculationResult - must be exposed as [DataContract] elements containing a number of [DataMember] fields or properties. This is not clear from the snippet of code you posted.