I have a WCF service which is returning PDF files as a stream over a NetTcp endpoint. This is all working fine. However, if the file is not found, or if I can't find the related row in the database to retrieve the filepath then I return Stream.Null from the service.
However I can't seem to find a way to compare the returning stream to check and see if it is empty or not.
I have tried the following:
If myStream IsNot Stream.Null
'Code to execute if stream isn't empty
End If
and
If Not streamPDF.Equals(Stream.Null)
'Code to execute if stream isn't empty
End If
But neither of these work as the code just carries on into the If block.
Any thoughts?
The Stream.Null is only your service scoped construct. For client you will get most probably empty stream => it will be same stream type as if you really send data.
It is strange design choice. If file doesn't exists it is "expected" exception and it should be handled with FaultContract and typed FaultException.
The Stream.Null field which redirect the stream that will not consume any operating system resources.
You can use Stream.Length property to check whether a stream is empty or not.
If your code runs on a different machine, it's normal. The null stream ("A Stream with no backing store" from the documentation) is not marshaled differently over the wire. On the client side, it's just a stream which always returns EOF.
If you need to carry some extra information, you need to find another way (other parameters /value information, exceptions), but not use the Stream itself, or use a data convention understood by both parties. For example "if the file is only 1 byte long and contains the character 255, then, it's the 'null stream'".
Related
I have an API endpoint for uploading large files, streaming then directly to DB. I use ASP.NET Core's IFormFeature to do this, calling IFormFile.OpenReadStream() to get a Stream that I pass to SqlClient for streaming.
I want to enforce a a maximum file size to avoid abuse. I know IFormFile has a Length property, but I assume that is based on Content-Length or similar and can not be trusted (please correct me if I'm wrong, but AFAIK the only way to be 100% sure about the file size is to actually read the data; the client could send an incorrect Content-Length.)
I must therefore ensure that when the stream is read, it does not read more than what is specified in IFormFile.Length (ideally it should throw if it encounters additional bytes). I have not found a way to do this. Is this possible, or is there perhaps a better way to ensure the server doesn't read enormous amounts of data from clients sending incorrect Content-Length headers?
(It should go without saying that this must not entail reading the entire file into memory.)
We are programming a MULE REST service which is divided in several layers.
The API layer (RAML-based) receives the inbound requests and prepares some flowVars so that the lower layers know how to proceed.
The second layer is also service defined, so there's one flow for each service oferred.
Finally, the third layer contains a unique flow and is the one which, depending on the flowVars configured in the upper layer, carries out a call using a HTTP Request component to the third-party service needed.
In this third layer, some audit registers are made in order to know what we are sending and what we are receiving. So, our audit component (a custom MULE connector) needs to write the content of the payload to our database, so a message.getPayloadAsString() (or similar) is needed. If we use a clean getter (like message.getPayload()), only the data type is obtained and thus written into the database.
The problem lays right in here. Every single payload received seems to be a BufferInputStream and, when doing the message.getPayloadAsString(), an inner casting seems to be affecting the payload. This, normally, wouldn't be a problem except for one of the cases that we have found: one of the services we invoke returns a PNG file, so message.getPayloadAsString() turns it into a String and breaks the image.
We've tried to clone the payload in order to keep one of the copies safe from the casting but, as an Object, it's not implementing Cloneable interface; we've tried to make a copy of the payload in any other single way, but only a new reference is generated; we've tried to serialize the payload to create a new copy from the serialized data but the Object doesn't either implement Serializable interface... Everything useless.
Any help, idea or piece of advice would be appreciated.
We finally managed to solve the problem by using message.getPayloadAsBytes();, which return value is a brand new byte[] object. This method doesn't either alter the payload within the message. By using the byte array we can create a String object to be written in our audit like this:
byte[] auditByteArray[] = message.getPayloadAsBytes();
String auditString = new String(auditByteArray);
Moreover, we tried a test consisting in stablishing that byte array as the new payload in the message and both JSON and PNG responses are managed correctly by the browser.
I want to build a wcf web service so that the client and the server would be able to transfer files between each other. Do you know how I can achieve this? I think I should turn it into a byte array but I have no idea how to do that. The file is also quite big so I must turn on streamed response.
It sounds like you're on the right track. A quick search of the interwebz yielded this link: http://www.codeproject.com/Articles/166763/WCF-Streaming-Upload-Download-Files-Over-HTTP
Your question indicates that you want to send a file from a java client to a WCFd endpoint, but the contents of your question indicate that this should be a bidirectional capability. If this is the case, then you'll need to implement a service endpoint on your client as well. As far as that is concerned, I cannot be of much help, but there are resources out there like this SO question: In-process SOAP service server for Java
As far as practical implementation, I would think that using these two links you should be able to produce some code for your server and client.
As far as reading all bytes of a file, in C# you can use: File.ReadAllBytes It should work as in the following code:
//Read The contents of the file indicated
string fileName = "/path/to/some/file";
//store the binary in a byte array
byte[] buffer = File.ReadAllBytes(fileName);
//do something with those bytes!
Be sure to use the search function in the future:
I have an application to upload files to a server. I am using nettcpbinding and wshttpbinding. When the files is larger than 200 MB, I get a memory exception. Working around this, I have seen people recommend streaming, and of course it works with nettcpbinding for large files (>1GB), but when using wshttpbinding, what would be the approach?? Should I change to basichttpbinding?? what?? Thanks.
I suggest you expose another end point just to upload such large size data. This can have a binding that supports streaming. In our previous project we needed to do file uploads to server as part of business process. We ended up creating 2 endpoints one just dedicated to file upload, and another for all other business functionality.
The streaming data service can be a generic service to stream any data to the server and maybe return a token for identifying the data on server.For subsequent requests this token can be passed along to manipulate the data on server.
If you don't want to (or cannot because of legit reasons) change the binding nor use streaming, what you can do is have some method with a signature along the lines of the following:
void UploadFile(string fileName, long offset, byte[] data)
Instead of sending the whole file, you send little packets, and tell where the data should be placed. You can add more data, of course, like the whole filesize, CRC of the file to know if the transfer was successful, etc.
I have WCF service that returns an object that contains an array of bytes that can be saved as a PDF (my .NET component of this implementation works like a charm, the bytes are saved to a stream and they write out the PDF without issue). I can modify the WCF to return just the bytes if necessary. My question is: How can I get those bytes to the asp page so I can save them. I've spent several hours searching the web for methods/help/hints/anything, but have been relatively unsuccessful. I have a method for writing files in asp, but it takes an array of bytes, but I dont know how to get the bytes from the WCF. The only way I've been able to communicate with WCF is to use SOAP type calls and parse the XML that is returned (which is fine for the rest of the page, since I just need the text values that are returned), but this one needs the bytes returned to save the file. (And no, the WCF cannot save the file on its own, it lives on a different server and does not have access to share a drive map or something like that).
Any thoughts/hints/tips/etc would be GREATLY appreciated, Im going insane with this project!
Thanks in advance everyone!
It sounds like you are calling the WCF service and getting a string in return, if not see Calling WCF service by VBScript.
Once you have the string, convert it to a byte sub type(using ChrB()) and save it to a file or write it out to the client.
I found this code sample at Create and work with binary data in ASP/VBScript:
Function StringToMultiByte(S)
Dim i, MultiByte
For i=1 To Len(S)
MultiByte = MultiByte & ChrB(Asc(Mid(S,i,1)))
Next
StringToMultiByte = MultiByte
End Function