Unable to pass MemoryStream parameter to WCF method? - c#

I have a method in Service1.svc.cs, below is the code
public void SaveData(int UserId, System.IO.MemoryStream File)
{
//Some code
}
I am passing values from xaml.cs
savedata.SaveDataAsync(userId, ms);
The error is
cannot convert from 'System.IO.MemoryStream' to
'SignSilverlight.ServiceReference1.MemoryStream'
How to solve ?

Memory stream is a .NET local object and it is not possible to pass it to a remote machine that might not even run .NET.
You have to pass a byte[] array instead. But be aware of size limits in endpoint's settings.
Here is how to (de)serialize a memory stream to array
// first endpoint
var streamSending = new MemoryStream();
var array = streamSending.ToArray();
// second endpoint
var streamRecieving = new MemoryStream(array);

Related

ByteArray to IFormFile

I am developing some REST API with C# and Net Core
I have a function in my repository which accepts a parameter of type IFormFile.
public async Task<bool> UploadFile(IFormFile file)
{
// do some stuff and save the file to azure storage
}
This function is called by a controller method which pass it the uploaded file
public class FileController : Controller
{
public async Task<IActionResult> UploadDoc(IFormFile file
{
// Call the repository function to save the file on azure
var res = await documentRepository.UploadFile(file);
}
}
Now I have another function that calls an external API which returns a file as a byte array. I'd like to save this byte array using the repository.UploadFile method but I can't cast the byte array object to IFormFile.
Is it possible?
You can convert the byte array to a MemoryStream:
var stream = new MemoryStream(byteArray);
..and then pass that to the constructor of the FromFile class:
IFormFile file = new FormFile(stream, 0, byteArray.Length, "name", "fileName");
Your repo shouldn't be using IFormFile. That's an abstraction that only applies to one particular method of HTTP file transfer (namely a multipart/form-data encoded request body). Something like your repo should have no knowledge of the source of the file (HTTP), nor how it was transmitted (multipart/form-data vs application/json for example).
Instead, you should use Stream for your param. In your UploadDoc action, then, you can simply do:
using (var stream = file.OpenReadStream())
{
await documentRepository.UploadFile(stream);
}
And, where you have just a byte array:
using (var stream = new MemoryStream(byteArray))
{
await documentRepository.UploadFile(stream);
}
You might also consider adding an overload of UploadFile that takes a byte[], as creating a new memory stream from a byte array just to have a stream is a waste of resources. However, a byte[] has to be handled differently than a Stream, so it may require some duplication of logic to go that route. You'll need to evaluate the tradeoffs.
Create a new MemoryStream based on the byte array.
Create a new FormFile object based on the MemoryStream.
Make sure to append the ContentDisposition header, otherwise you will be unable to operate your FormFile object as a C# exception will be thrown.
The complete code:
using (var stream = new MemoryStream(byteArray))
{
var file = new FormFile(stream, 0, byteArray.Length, name, fileName)
{
Headers = new HeaderDictionary(),
ContentType = contentType,
};
System.Net.Mime.ContentDisposition cd = new System.Net.Mime.ContentDisposition
{
FileName = file.FileName
};
file.ContentDisposition = cd.ToString();
}

My stream keeps throwing Read/Write Timeout exceptions

I am parsing a PowerPoint presentation using Open Office SDK 2.0. At one point in the program I'm passing a stream to a method that will return an image's MD5. However, there seems to be a problem in the stream, before it even gets to my MD5 method.
Here's my code:
// Get image information here.
var blipRelId = blip.Embed;
var imagePart = (ImagePart)slidePart.GetPartById(blipRelId);
var imageFileName = imagePart.Uri.OriginalString;
var imageStream = imagePart.GetStream();
var imageMd5 = Hasher.CalculateStreamHash(imageStream);
In debug, before I let it drop into Hasher.CalculateStreamHash, I check the imageStream properties. Immediately, I see that the ReadTimeout and WriteTimeout both have similar errors:
imageStream.ReadTimeout' threw an exception of type 'System.InvalidOperationException
imageStream.WriteTimeout' threw an exception of type 'System.InvalidOperationException
Here's a picture of the properties that I"m seeing during debug, in case it helps:
This code is running over a PowerPoint presentation. I'm wondering if the fact that it's zipped (a PowerPoint presentation is basically just a zipped up file) is the reason I'm seeing those timeout errors?
UPDATE: I tried taking the stream, getting the image and converting it to a byte array and sending that to the MD5 method as a memory stream, but I still get those same errors in the Read/Write Timeout properties of the stream. Here's the code as it is now:
// Get image information here.
var blipRelId = blip.Embed;
var imagePart = (ImagePart)slidePart.GetPartById(blipRelId);
var imageFileName = imagePart.Uri.OriginalString;
var imageStream = imagePart.GetStream();
// Convert image to memory stream
var img = Image.FromStream(imageStream);
var imageMemoryStream = new MemoryStream(this.imageToByteArray(img));
var imageMd5 = Hasher.CalculateStreamHash(imageMemoryStream);
For clarity, here's the signature for the CalculateStreamHash method:
public static string CalculateStreamHash([NotNull] Stream stream)
Mischief managed! I was able to overcome this problem by using a BufferedStream and adding an overloaded method to my MD5 method that accepted a BufferedStream as a parameter:
// Get image information here.
var blipRelId = blip.Embed;
var imagePart = (ImagePart)slidePart.GetPartById(blipRelId);
var imageFileName = imagePart.Uri.OriginalString;
// Convert image to buffered stream
var imageBufferedStream = new BufferedStream(imagePart.GetStream());
var imageMd5 = Hasher.CalculateStreamHash(imageBufferedStream);
...and:
public static string CalculateStreamHash([NotNull] BufferedStream bufferedStream)

ByteArray class for C#

I'm trying to translate a function from ActionScript 3 into C# .NET.
What I have trouble is how to properly use ByteArrays in C#. In As3 there is a specific Class for it that already has most of the functionality i need, but in C# nothing of that sort seems to exist and I can't wrap my head around it.
This is the As3 function:
private function createBlock(type:uint, tag:uint,data:ByteArray):ByteArray
{
var ba:ByteArray = new ByteArray();
ba.endian = Endian.LITTLE_ENDIAN;
ba.writeUnsignedInt(data.length+16);
ba.writeUnsignedInt(0x00);
ba.writeUnsignedInt(type);
ba.writeUnsignedInt(tag);
data.position = 0;
ba.writeBytes(data);
ba.position = 0;
return ba;
}
But from what I gather, in C# I have to use a normal Array with the byte type, like this
byte[] ba = new byte[length];
Now, I looked into the Encoding Class, the BinaryWriter and BinaryFormatter class and researched if somebody made a Class for ByteArrays, but with no luck.
Can somebody nudge me in the right direction please?
You should be able to do this using a combination of MemoryStream and BinaryWriter:
public static byte[] CreateBlock(uint type, uint tag, byte[] data)
{
using (var memory = new MemoryStream())
{
// We want 'BinaryWriter' to leave 'memory' open, so we need to specify false for the third
// constructor parameter. That means we need to also specify the second parameter, the encoding.
// The default encoding is UTF8, so we specify that here.
var defaultEncoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier:false, throwOnInvalidBytes:true);
using (var writer = new BinaryWriter(memory, defaultEncoding, leaveOpen:true))
{
// There is no Endian - things are always little-endian.
writer.Write((uint)data.Length+16);
writer.Write((uint)0x00);
writer.Write(type);
writer.Write(data);
}
// Note that we must close or flush 'writer' before accessing 'memory', otherwise the bytes written
// to it may not have been transferred to 'memory'.
return memory.ToArray();
}
}
However, note that BinaryWriter always uses little-endian format. If you need to control this, you can use Jon Skeet's EndianBinaryWriter instead.
As an alternative to this approach, you could pass streams around instead of byte arrays (probably using a MemoryStream for implementation), but then you will need to be careful about lifetime management, i.e. who will close/dispose the stream when it's done with? (You might be able to get away with not bothering to close/dispose a memory stream since it uses no unmanaged resources, but that's not entirely satisfactory IMO.)
You want to have a byte stream and then extract the array from it:
using(MemoryStream memory = new MemoryStream())
using(BinaryWriter writer = new BinaryWriter(memory))
{
// write into stream
writer.Write((byte)0); // a byte
writer.Write(0f); // a float
writer.Write("hello"); // a string
return memory.ToArray(); // returns the underlying array
}

Getting Json Output from Byte Array

I just started a new project on WCF and to be honest I'm very new at this with limited knowledge.
So what I'm trying to do is open a file that is stored in my computer (e.g. word, pdf, etc.) and display the contents in the webpage in JSon format. I converted the file in a byte array and tried to display the Stream. When I did that it asked me to open the file or save it. I don't want that - I just want the contents of the file to be displayed on my local host when i call the method.
Here's what I have:
public string GetRawFile()
{
string file = #"C:\.....\TestFile.pdf";
byte[] rawFile = File.ReadAllBytes(file);
//Stream stream = new MemoryStream(rawFile);
//DataContractJsonSerializer obj = newDataContractJsonSerializer(typeof(string));
//string result = obj.ReadObject(stream).ToString();
//Deserializing
MemoryStream stream = new MemoryStream();
BinaryFormatter binForm = new BinaryFormatter();
stream.Write(rawFile, 0, rawFile.Length);
stream.Seek(0, SeekOrigin.Begin);
Object obj = (Object) binForm.Deserialize(stream);
System.Web.Script.Serialization.JavaScriptSerializer xyz = new System.Web.Script.Serialization.JavaScriptSerializer();
string ejson = xyz.Serialize(obj);
WebOperationContext.Current.OutgoingRequest.ContentType = "text/json";
return ejson;
}
I'm trying to return a string and it's not working, but when I return just the stream it's popping up the "openwith" message.
Also should I use the GET or POST on my datacontract. I'm using REST in C#.
I'm assuming that your file actually contains json. If that is the case just do this;
string file = File.ReadAllText("C:\path\to\file.extension");
You're making the problem a lot more complicated than it needs to be. Just read the file and return it's data as a string. I think you want to use GET for the http method. Generally speaking, you all use post if you're adding new content. If for example the users request would cause the application to write some data to a file or data base then you would typically use POST for the http method. If they're just requesting data, you almost always use GET.

How to pass through the soap memory stream?

I create memory stream.
var memoryStream = new MemoryStream();
var binaryFormatter = new BinaryFormatter();
binaryFormatter.Serialize(memoryStream, list.ToArray());
And I need to pass through the soap to java server and insert to database.
And how create webService method ?
#WebMethod(operationName = "CreateObject")
public String CreateTopology(
#WebParam(name = "session")int id_session,
#WebParam(name = "title") String title,
#WebParam(name = "content") Object content,
#WebParam(name = "access") Integer access) {
EDIT:
Problem. I have serialized object in C #. I need to pass it on to the server via SOAP Java, after that save it in MySQL database in field of type Blob (may not be the blob)
Have a look here:
//build a Call object
Call call = new Call();
call.setTargetObjectURI("urn:greetingService");
call.setMethodName("sayGreeting");
call.setEncodingStyleURI(Constants.NS_URI_SOAP_ENC);
//creating a parameter list
Vector params = new Vector();
params.addElement(new Parameter("name", String.class, name,null));
//adding the parameter(s) to the Call object
call.setParams(params);
You are setting the method-name "sayGreeting" and in a vector params you specify the parameters which the method will be called with. This parameter-vector is what you need!
The code-sample is taken from page 2 of this tutorial which i very much recommend: http://javaboutique.internet.com/tutorials/SOAP/
base64String - to pass as string
var memoryStream = new MemoryStream();
var binaryFormatter = new BinaryFormatter();
binaryFormatter.Serialize(memoryStream, m_workspace.ListPlatforms.ToArray());
String base64String = Convert.ToBase64String(memoryStream.ToArray());

Categories