Byte array as an out parameter not recognized - c#

I had a webmethod working which returned a byte array to the caller:
public byte[] DownloadPDF(string URI)
I had to change this to return another output (a string). So, I decided to change the method completely by now returning void and having 3 parameters like this:
public void DownloadFile(string URI, out byte[] docContents, out string returnFiletype)
My web service compiles correctly but I suspect something is wrong with the 2nd parameter (i.e. the byte array) because when I "Add Web Reference" and build my proxy class, the method has only 2 parameters, not 3):
[System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://tempuri.org/DownloadFile", RequestNamespace="http://tempuri.org/", ResponseNamespace="http://tempuri.org/", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
[return: System.Xml.Serialization.XmlElementAttribute("docContents", DataType="base64Binary")]
public byte[] DownloadFile(string URI, out string returnFiletype) {
object[] results = this.Invoke("DownloadFile", new object[] {
URI});
returnFiletype = ((string)(results[1]));
return ((byte[])(results[0]));
}
I don't see why my 2nd parameter, the byte array, is being ignored, but it appears to be the source of the problem.
This of course messes me up in the web client app where I get an error message at compile time:
No overload for method 'DownloadFile' takes '3' arguments
Here is the code in the web client where I need to pass 3 arguments:
myBrokerASMXProxy.ASMXProxy.FileService client = new myASMXProxy.ASMXProxy.FileService();
byte[] fileDataBytes;
string fileType;
client.DownloadFile(URI, fileDataBytes, fileType);
I am thinking of changing it back to return a byte array and add just a single "out" parameter but I thought I should ask you experts about this and in general, what is the best practice for handling multiple output requirements.

Why don't your try putting this signature:
public bool DownloadFile(string URI, out byte[] docContents, out string returnFiletype)
To see what happens? I agree with Jon Skeet, but you can still can return a bool with the result of the operation

The byte array isn't being ignored - it's being put as the return type instead. I don't know why it's doing that, but it makes more sense in my view. I wouldn't use out parameters in a void method. I suspect the proxy generator just takes any method with out parameters and turns the first one into a return type.

Related

System.IO.BACnet - send ReadPropertyMultiple without specifying BacnetPropertyReference->propertyArrayIndex

I am using System.IO.BACnet library for my C# BACNet client.
I am trying to send to server "ReadPropertyMultiple" request, however I am unable to read non-array BACNet properties, since the System.IO.BACnet.BacnetClient.ReadPropertyMultipleRequest requires list of System.IO.BACnet.BacnetPropertyReference(s) ...
public bool ReadPropertyMultipleRequest(BacnetAddress address, BacnetObjectId objectId, IList<BacnetPropertyReference> propertyIdAndArrayIndex, out IList<BacnetReadAccessResult> values, byte invokeId = 0);
.. and the System.IO.BACnet.BacnetPropertyReference requires propertyArrayIndex ..
public struct BacnetPropertyReference
{
public uint propertyIdentifier;
public uint propertyArrayIndex;
public BacnetPropertyReference(uint id, uint arrayIndex);
public BacnetPropertyIds GetPropertyId();
public override string ToString();
}
.. which, when not set, defaults to 0. This causes, that after request with this list is sent, all properties are requested with propertyArrayIndex: 0, which fail for non-array object properties.
Example:
Request:
Response:
What is the right way to not add the propertyArrayIndex into request and thus be able to read non-array properties with ReadPropertyMultiple request?
If you request array-index "0" you should (in theory) receive the number of (following) elements, and not the full list of values (/remaining elements containing values).
Can't you use (the) 'Read-Property' (service) for non-array items (?).
The solution is to set propertyArrayIndex = uint.MaxValue.
For example:
BacnetPropertyReference reff = new BacnetPropertyReference((uint) BacnetPropertyIds.PROP_PRESENT_VALUE, uint.MaxValue);

Serialize object from a string?

I have a class like this:
using UnityEngine;
[System.Serializable]
public class PlayerInfo
{
public string playerId;
public string deviceId;
public static PlayerInfo CreateFromJSON(string jsonString)
{
return JsonUtility.FromJson<PlayerInfo>(jsonString);
}
}
And my client receives updates with a function like this:
void OnPlayerLocalJoin(Socket socket, Packet packet, params object[] args)
{
Debug.Log(args[0]);
}
According to the documentation (which need more detail), the args should use the default json decoder, but I see it returns args as System.Object[], but oddly enough when I try args[0] my log returns:
System.Collections.Generic.Dictionary`2[System.String,System.Object]
When I print out the raw "packet" object, I do see my object:
[ "playerLocalUpdate", {"playerId":"abc","deviceId":"150B"} ]
No matter what I try, I cannot get the second part of this array to be a dictionary or better yet, how can I get it to be an instance of PlayerInfo
Debug.Log(packet.ToString());
var serialized = JsonUtility.ToJson(packet.ToString());
Debug.Log(serialized);
I'm trying to follow the docs: https://besthttp-documentation.readthedocs.io/en/latest/#3.%20Socket.IO/2%20Subscribing%20and%20receiving%20events/
The easy bit is you want to do
PlayerInfo newPlayerInfo = PlayerInfo.CreateFromJSON(jsonString);
where jsonString is '{"playerId":"abc","deviceId":"150B"}'. We can see that from the Unity docs. I think you've worked that out already.
As you say, you can see this string arriving in your packet. As you also say, it's not clear from the HTTP/2 docs what args contains. Although the dictionary may be the string we want converted to a dictionary, which isn't much use to us. You could investigate further by casting args[0] to Dictionary<string, object> and then doing a foreach on it and logging the results. I'm also unclear what args[1] might contain?
Maybe it is best to get it out of the packet. My guess is that to get the jsonString you need to do something like:
var packetArray = JsonUtility.FromJson<object[]>(packet.ToString());
string jsonString = packetArray[1].ToString();
That's because packet is JSON and we want to convert FROM the JSON string (which represents an array) to a C# array. Then we want the second item in the array. I think. It's hard to be sure without access to the code.

Which way is better for this method that writes to a file? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 5 years ago.
Improve this question
A bit of a silly question but i really cant decide, which was is better?
Either:
// Writes a byte array at offset in file
public void WriteByteArray(string file, long offset, byte[] buffer)
but that will force the user to always write the file path, or have it like this:
private string path;
public string File
{
get { return path; }
set { path = value; }
}
// Will do the same thing as the method above just here,
// except it will use the path which was set via "File"
public void WriteByteArray(long offset, byte[] buffer)
There are pros and cons for both. For the first way the pro is, if you want to write the byte array into different files then you can easily do:
WriteByteArray(file_1, 0, new byte[]);
WriteByteArray(file_2, 0, new byte[]);
WriteByteArray(file_3, 0, new byte[]);
but the con is, if you want to just write to one file then constantly typing that path or the string variable containing the path may make the code look a bit messy and unorganized.
The pros for the second way is basically the con for the first way all you do is:
File = "C:\\test.bin";
WriteByteArray(0, new byte[]);
WriteByteArray(0xFF, new byte[]);
WriteByteArray(0x2ACD, new byte[]);
but the con is the pro for the first way aka if you want to write the byte array into different file then you will always have to do File =...
Idk. Which is better? Which way is mostly used?
Since you feel there are pros and cons to both, then just implement both. This seems like a case where there is sufficient demand for either option, and creating one does not preclude the creation of another.
Also, since the first one doesn't require any state variables, make it static so the caller doesn't have to instantiate something just to call it.
Then have your instance method (that uses the File property) call the static method:
class FileWrapper
{
public string File { get; set; }
public static void WriteByteArray(string file, long offset, byte[] buffer)
{
// The real work goes here
}
public void WriteByteArray(long offset, byte[] buffer)
{
// Just call the static method and pass the instance property for the file path
WriteByteArray(this.File, offset, buffer);
}
}
The two interfaces are for entirely different use cases:
The first method, which could be made static, is for writing a buffer to a file at once; there should be no continuations, because the same file could be written in between of your program's writing it, creating a confusion.
The second method is for building a file incrementally from partial buffers. You set the file once, and then write to it until you are done. The class itself should have a Dispose method in order to participate in using statement.
Ultimately, the decision is up to you: pick the interface that matches your intended usage pattern.
Note: Note that since offset could mean an offset in a file or an offset in the buffer, consider renaming the second parameter to fileOffset or filePosition.
The second approach introduces sequential coupling, which is often an anti-pattern (and probably is in this case). It also introduces a global variable (see global variables are bad). So the first method is better (although there is probably a third option that is even better, such as creating an object like FileStream).
But assuming you want to choose from either the first option or second option, pick the first. If you are concerned about code turning out like this....
WriteByteArray(someLongVariableYouDontWantToType, myArray1);
WriteByteArray(someLongVariableYouDontWantToType, myArray2);
WriteByteArray(someLongVariableYouDontWantToType, myArray3);
WriteByteArray(someLongVariableYouDontWantToType, myArray4);
...I suggest you do this (which will also perform better)...
var outputBuffer = new List<byte>();
outputBuffer.AddRange(myArray1);
outputBuffer.AddRange(myArray2);
outputBuffer.AddRange(myArray3);
outputBuffer.AddRange(myArray4);
WriteByteArray(someLongVariableYouDontWantToType, outputBuffer.ToArray());
Or
WriteByteArray
(
someLongVariableYouDontWantToType,
(new[] { myArray1, myArray2, myArray3, myArray4 }).SelectMany(a => a)
);
...both of which concatenate the arrays and write them all in one go. The latter will perform better, but not everyone finds that sort of LINQ code easy to read.
If you did not mean to concatenate, but wish to replace, you should of course just use File.WriteAllBytes().
Since you expect to operate on the same file multiple times, it may be appropriate to use a Builder pattern to solve this problem. Or maybe it isn't. But it's interesting to discuss and could work as a decent answer. Let's have some fun and check it out!
Under the builder pattern, instead of this
WriteByteArray(someLongVariableYouDontWantToType, index1, myArray1);
WriteByteArray(someLongVariableYouDontWantToType, index2, myArray2);
WriteByteArray(someLongVariableYouDontWantToType, index3, myArray3);
WriteByteArray(someLongVariableYouDontWantToType, index4, myArray4);
You'd want your code to look something like this:
myFile
.WriteByteArray(index1, myArray1)
.WriteByteArray(index2, myArray2)
.WriteByteArray(index3, myArray3)
.WriteByteArray(index4, myArray4);
The first step is to create a type that will hold a string that is the file name. We want our own specific type for reasons that will become apparent in a moment. Here's a sample:
public class File
{
public string Path {get; private set; }
public File(string path)
{
Path = path;
}
}
You can use this class like this:
var myFile = new File("c:\temp\MyFileName.txt");
Now that we have a class, we can write an extension method on it:
static public class ExtensionMethods
{
static public File WriteBytes(this File path, int offset, IEnumerable<byte> buffer)
{
OpenFile(path); //Just as an example
SeekIndex(offset); //Just as an example
Write(buffer); //Just as an example
CloseFile(); //Just as an example
return path;
}
}
The key here is the return path line. Because of that, you can chain these together. Now we can do this:
File file = "c:\temp\fileName.txt";
file
.WriteByteArray(index1, myArray1)
.WriteByteArray(index2, myArray2)
.WriteByteArray(index3, myArray3)
.WriteByteArray(index4, myArray4);
Why did we want to use File and not just a string? Well, it would be pretty gauche to write an extension method for string that only works on certain types of strings. Hence the file-specific type.
Now there is one more (small) problem. Each call to WriteByteArray will probably open the file and close it again, which seems inefficient, since we only need to do that once. So in keeping with the builder pattern, we can add another method to signal completion.
static public class ExtensionMethods
{
static public File WriteBytes(this File path, int offset, IEnumerable<byte> buffer)
{
if (!IsFileOpen) OpenFile(path);
SeekIndex(offset);
Write(buffer);
return path;
}
static public void Commit(this File path)
{
CloseFile();
}
}
...which you can use like this:
File file = "c:\temp\fileName.txt";
file
.WriteByteArray(index1, myArray1)
.WriteByteArray(index2, myArray2)
.WriteByteArray(index3, myArray3)
.WriteByteArray(index4, myArray4)
.Commit();
This last part isn't mandatory, but may be a good idea if I/O performance is important to you.

HttpPost how to receive parameters c#

I have a method on web service and I need to receive parameters with [HttpPost].
I am new at this, and I really don't know how.
I need to receive the following:
**** long requestId, string text, byte[] audio, short languageId****
public void AddAnswer (long requestId, string text, byte[] audio, short languageId)
{
string userIdWhoAnswers = (User as TokenPrincipal).userId.ToString();
long userId = Convert.ToInt64(userIdWhoAnswers);
using (var context = new WordsEntities())
{
Answers answer = new Answers();
answer.requestId = requestId;
answer.userId = 10;
answer.text = text;
answer.audioExtension = audio;
DateTime datee = DateTime.Now;
answer.timePosted = datee;
answer.languageId = languageId;
context.Answers.Add(answer);
context.SaveChanges();
}
}
This is my method but with HttpGet, I need to convert it to HttpPost.
Can someone please help me?
Looking your code I think you are sending the information using the body and not the url (in fact you are trying to send a byte array that usually isn't compatible with the query string).
For this reason you have to use the FromBody attribute near to the parameter name
public void AddAnswer ([FromBody] long requestId, [FromBody] string text, [FromBody] byte[] audio, [FromBody] short languageId)
moreover I think that the byte[] doesn't work. Probably you have to work with multipart
you can refer to this question and specially this link
TLDR; FromBody accepts just one parameter; try passing a JSON string with all required inputs in a single parameter to your HttpPost.

Webservice.asmx not receiving parameters with POST/SOAP requests

I am trying to send data to a C# (actually Mono) webservice from a PHP environment. Oddly, the webservice works correctly when I call it with a browser URL (i.e. with the GET method).
However, calling it from my PHP script shows that no parameter is received on Mono's side.
Here is my PHP call:
$domoWSHeader->setAuthenticatedToken($resultAuthentification->AuthentificationResult);
$inputHeaders = new SoapHeader("http://tempuri.org/domo", "DomoWSHeader", $domoWSHeader, false);
$result = $soapClient->__soapCall("MyWebServiceMethod", array("idLight"=>$uuid), NULL, $inputHeaders);
And the Webservices.asmx looks like:
namespace domo
{
public class DomoWSHeader : System.Web.Services.Protocols.SoapHeader
{
public string username;
public string password;
public string authenticatedToken;
}
[WebMethod]
public bool MyWebServiceMethod(int idLight)
{
bool success = false;
//Snip
return success;
}
}
What have I tried?
Trying to declare [System.Web.Services.Protocols.SoapHeader("DomoWSHeader")] before the method didn't change the behaviour.
I also tried to edit the web.config file to add protocols in it. I am totally new to the C# world, and I am not sure where to find answers to this problem. I hope one of you can help me understand what happens here.
Found the origin of the problem from PHP.NET : http://php.net/manual/fr/soapclient.soapcall.php#110390
In the PHP code, the parameters in the "__soapCall()" method were :
$parameters = array("idLight" => $uuid);
but it's correct when you use them to call the webservice method directly as :
$soapClient->NameOfTheMethod($parameters);
In my case, i'd need to call the webservice method with "__soapCall()" because i use headers for authentication, and the PHP.NET documentation says that we must encapsulate the array of parameters into another array like this :
$soapClient->__soapCall("NameOfTheMethod", array($parameters), NULL, $inputHeaders);
(Note that the 3rd and the 4th parameters in the "__soapCall()" method are optionals but i use them)
Hope this help :)

Categories

Resources