Http Post a Stream in F# without reading into a Byte Array - f#

With C# I can use the System.Net.Http Library to post a stream directly like so:
private async Task UploadFileAsync(Uri uri, string filename)
{
using (var stream = File.OpenRead(filename))
using (var client = new HttpClient())
{
await client.PostAsync(uri, new StreamContent(stream));
}
}
Is there a way to do this in F# in a functionally idiomatic way?
FSharp.Data.Http.Request lets you post Binary data but requires a byte array to do so, which means reading the stream into memory. I'd like to avoid this as I am posting > 20Mb.

Doing this in a functionally idiomatic way would involve some kind of IO monad. As F# is a mixed paradigm language e.g.
let uploadFile (uri: Uri) fileName =
async {
use stream = File.OpenRead fileName
use client = new HttpClient()
return! client.PostAsync(uri, new StreamContent(stream)) |> Async.AwaitTask
}
is perfectly acceptable IMHO.

Related

What is the alternative for jsonp format in MVC core?

I need to return result in jsonp format while I'm using asp.net MVC Core.
In asp.net MVC we can use MVC.jsonp dll an it's work fine but what is the alternative in MVC Core because I can't find any.
public JsonpResult FunctionalitesTblList()
{
var settings = new JsonSerializerSettings();
return Jsonp(Rows, settings);
}
There was no built in ability to handle JSONP with MVC, so you were always using a third-party addition. Apparently, that library is incompatible with .NET Core. Therefore, your option is to find a similar library that is compatible or choose some other approach.
#CuongLe is correct that CORS is a better approach overall, so you should definitely investigate that. However, if you insist on JSONP, it's so simple to implement manually, you don't really need a library.
Simply, all JSONP is a is JSON passed into a "callback" function, specified by the client. In other words, if the callack was specified as "mycallback", the response should just look like:
mycallback({ "foo": "bar" });
As a result, your code simply becomes:
string json = null;
using (var ms = new MemoryStream())
{
var serializer = new DataContractJsonSerializer(typeof(Foo));
serializer.WriteObject(ms, foo);
json = Encoding.UTF8.GetString(ms.ToArray());
}
var jsonp = String.Format("{0}({1});", callback, json);
Response.ContentType = "application/javascript";
return Content(jsonp);

Blackberry-not getting soap response xml

I am trying to consume SOAP response xml by passing request xml in a string, using BlackBerry Java plugin for Eclipse. I have been struck on this for the past two days looking for a way to solve it.
I have attached the sample code below.
public String CheckXml()
{
final String requestXml="<SOAP:Envelope xmlns:SOAP=\"http://schemas.xmlsoap.org/soap/envelope/\"><header xmlns=\"http://schemas.cordys.com/General/1.0/\"></header><SOAP:Body><authenticateAgainstOID xmlns=\"http://schemas.cordys.com/OIDAuthentication\"><stringParam>HEMANTS_MUM013</stringParam><stringParam1>TATA2012</stringParam1></authenticateAgainstOID></SOAP:Body></SOAP:Envelope>";
final String HOST_ADDRESS = "http://xyz.com/cordys/com.eibus.web.soap.Gateway.wcp?organization=o=B2C,cn=cordys,cn=cbop,o=tatamotors.com&SAMLart=MDFn+8e5dRDaRMRIwMY7nI84eEccbx+lIiV0VhsOQ7u+SKG6n5+WNB58";
String result="";
try {
HttpConnection url=(HttpConnection)Connector.open(HOST_ADDRESS);
url.setRequestProperty("Content-Type", "text/xml");
url.setRequestMethod(HttpConnection.GET);
OutputStreamWriter writer=new OutputStreamWriter(url.openOutputStream());
writer.write(requestXml);
writer.flush();
writer.close();
StringBuffer buffer1=new StringBuffer();
InputStreamReader reader=new InputStreamReader(url.openInputStream());
StringBuffer buffer=new StringBuffer();
char[] cbuf=new char[2048];
int num;
while (-1 != (num = reader.read(cbuf))) {
buffer.append(cbuf, 0, num);
}
String result1 = buffer.toString();
} catch (Exception e) {
System.out.println(e);
}
return result;
}
I think the main issue that you aren't asking http. getResponseCode(). I think BB doesn't do any interaction until you call it.
I would also be careful with this code on the real devices. Search for correct opening connection on the BlackBerries.
I noticed that you are not including the SoapAction header in the request.
SOAP Web services usually have a fixed URL, and the differents methods are selected with the SoapAction header. You can check the header by opening the WSDL in a browser and inspecting the format for the method you want to invoke.
Once you know which action to select, set it as a regular http header:
url.setRequestProperty("SOAPAction", <your action here>);
Another source of problems in your code is that you are using the old HttpConnection class that requires appending a suffix to the URL depending on the transport type (MDS, BIS, Wi-Fi, etc). You don't need to use this legacy class unless you are targeting OS 4.5 and lower. So have a look at ConnectionFactory class, which is much easier to use. It is available since OS 5.0.

ASP.Net MVC & WebAPI encryption

I want to utilise some form of "simple" encryption that is reasonably secure but very low friction in terms of impact on development process.
Supposing I own both sides of the conversation in a client <> web service situation. My application is a windows phone/win8/silverlight/desktop app and the server is ASP.Net MVC or WebAPI.
In my mind, I want something as simple as:-
<security encryption="off|sometype|someothertype">
<privatekey>12345MyKey54321</privatekey>
</security>
as some form of configuration parameter on both the client and server. Additionally an authentication routine will return and store some form of public key.
Doing so will enable the 'encryption mode' and result in any http requests being encrypted & hashed in the selected manner using the provided keys. The end result being anything sniffed on the local, proxy or remote machines would not be able to view the data without the key and decryption method. On the server, data is decrypted using the same key before hitting controller actions.
Other than swapping out HttpRequest/WebClient calls for something like EncryptedHttpRequest and adding the appropriate hook on the MVC/WebAPI side of things, all other client code and controller actions would be ignorant to the fact the data was encrypted.
Am I missing something or could setup not be this simple? As far as I have searched there is nothing that offers this level of simplicity so I figure I'm missing some gaping flaw in my logic?
All you are looking for can be achieved by simply using HTTPS. Just buy a certificate (or use a self-signed certificate) and there is your encryption.
Do not re-invent the wheel.
I've done this successfully. It isn't too difficult and works well. I use it for activating a license for a product. The most important thing is that your truly control the client and server - no one can extract your private key from your code on the client.
Step 1: Create an MVC controller action method that takes no arguments:
[HttpPost] public ActionResult Activate() { ... }
Step 2: In the controller just use the HttpRequest.InputStream to get ahold of the bytes sent from the client.
var stream = this.HttpContext.Request.InputStream;
Step 3: Create a CryptoStream to deserialize.
I've included creating both encryption and decryption examples here. The sharedSecret is a byte[] of sufficient length (512 bytes) of random bytes - this is what you protect!
public CryptoStream CreateEncryptionStream(Stream writeStream)
{
TripleDESCryptoServiceProvider cryptoProvider = new TripleDESCryptoServiceProvider();
PasswordDeriveBytes derivedBytes = new PasswordDeriveBytes(this._sharedSecret, null);
CryptoStream cryptoStream = new CryptoStream(writeStream, cryptoProvider.CreateEncryptor(derivedBytes.GetBytes(16), derivedBytes.GetBytes(16)), CryptoStreamMode.Write);
return cryptoStream;
}
public CryptoStream CreateDecryptionStream(Stream readStream)
{
TripleDESCryptoServiceProvider cryptoProvider = new TripleDESCryptoServiceProvider();
PasswordDeriveBytes derivedBytes = new PasswordDeriveBytes(this._sharedSecret, null);
CryptoStream cryptoStream = new CryptoStream(readStream, cryptoProvider.CreateDecryptor(derivedBytes.GetBytes(16), derivedBytes.GetBytes(16)), CryptoStreamMode.Read);
return cryptoStream;
}
Step 4: Use your CryptoStream another stream reader to decrypt.
I use an XmlReader so that all my existing serialization code can work either in the clear (when reading/writing to disk or database on the server) or encrypted (when transmitting).
using (var reader = XmlReader.Create(decryptionStream, settings)) { ... }
Step 5: Formulate a secure response in your controller.
This is doing the reverse of Steps 1-4 to encrypt your response object. Then you just write your encrypted response to a memory stream and return it as a File result. Below, I've shown how I do this for my license response object.
var responseBytes = GetLicenseResponseBytes(licenseResponse);
return File(responseBytes, "application/octet-stream");
private byte[] GetLicenseResponseBytes(LicenseResponse licenseResponse)
{
if (licenseResponse != null)
{
using (MemoryStream memoryStream = new MemoryStream())
{
this._licenseResponseSerializer.Write(memoryStream, licenseResponse);
return memoryStream.ToArray();
}
}
return null;
}
Step 6: Implement your client request response.
You can use HttpWebRequest or the WebClient classes to formulate the request. Here's a couple of examples from the code I use.
byte[] postBytes = GetLicenseRequestBytes(licenseRequest);
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(licenseServerUrl);
request.Method = "POST";
request.ContentType = "application/octet-stream";
request.Proxy = WebRequest.DefaultWebProxy;
using (Stream requestStream = request.GetRequestStream())
{
requestStream.Write(postBytes, 0, postBytes.Length);
}
return request;
private LicenseResponse ProcessHttpResponse(HttpWebResponse response)
{
if ((response.StatusCode == HttpStatusCode.OK) && response.ContentType.Contains("application/octet-stream"))
{
var stream = response.GetResponseStream();
if (stream != null)
{
var licenseResponse = this._licenseResponseSerializer.Read(stream);
return licenseResponse;
}
}
return new LicenseResponse(LicensingResult.Error);
}
Summary and Tips
Use the streams in the request/responses on the client and server to communicate binary octet-stream data
Use CryptoStream along with an encryption algorithm (consider using the strongest encryption possilbe) and a good private key to encrypt data when you serialize/deserialize it.
Make sure to check the size and format all incoming data to the client and server (avoid buffer overruns and throw exceptions early)
Protect your private key on your client using obfuscation if possible (take a look at the DeepSea obfustactor)

Is an MVC Async controller that calls WebResponse still async?

We have a large library that makes a lot of HTTP calls using HttpWebRequest to get data. Rewriting this library to make use of async calls with the HTTPClient would be a bear. So, I was wondering if I could create async controllers that use a taskfactory to call into our library and whether the calls that are ultimately made via the WebClient would be asynch or they would still be synch. Are there any problems/side-effects I might cause by trying to mix async with the old HttpWebRequest?
If I'm understanding what you're proposing the answer is: no, changing the services the client talks to to be async would not help. The client would still block a CPU thread while the I/O is outstanding with the server, whether the server is async or not.
There's no reason to switch away from HttpWebRequest. You can use TaskFactory::FromAsync in .NET 4.0 to call HttpWebRequest::BeginGetResponse. That looks something like this:
WebRequest myWebRequest = WebRequest.Create("http://www.stackoverflow.com");
Task<WebResponse> getResponseTask = Task<WebResponse>.Factory.FromAsync(
myWebRequest.BeginGetResponse,
myWebRequest.EndGetResponse,
null);
getResponseTask.ContinueWith(getResponseAntecedent =>
{
WebResponse webResponse = getResponseAntecedent.Result;
Stream webResponseStream = webResponse.GetResponseStream();
// read from stream async too... eventually dispose of it
});
In .NET 4.5 you can still continue to use HttpWebRequest and use the new GetResponseAsync method with the new await features in C# to make life a heck of a lot easier:
WebRequest myWebRequest = WebRequest.Create("http://www.stackoverflow.com");
using(WebResponse webResponse = await myWebRequest.GetResponseAsync())
using(Stream webResponseStream = webResponse.GetResponseStream())
{
// read from stream async, etc.
}

Using ConnectionFactory and retrieve the data from url

public class ConsumeFactoryThread extends Thread {
private String url;
public ConsumeFactoryThread(String url){
this.url = url;
}
public void run(){
ConnectionFactory connFact = new ConnectionFactory();
ConnectionDescriptor connDesc;
connDesc = connFact.getConnection(url);
if(connDesc != null)
{
HttpConnection httpConn;
httpConn = (HttpConnection) connDesc.getConnection();
try
{
final int iResponseCode = httpConn.getResponseCode();
UiApplication.getUiApplication().invokeLater(new Runnable()
{
public void run()
{
//data retrieved
}
});
}
catch(IOException e)
{
System.err.println("Caught IOException: " + e.getMessage());
}
}
}
}
I got the above code from one of Blackberry's articles, but I'm not entirely sure as to how I get the raw String of the contents of the url, which in my case is going to be a json string.
I know when I was not using ConnectionFactory I used an inputstream to get the data, but I don't know if it is the same with the newer api.
Thanks
I believe what you are looking to do is the following:
is = ((Connection) httpConn).openInputStream();
byte[] data = net.rim.device.api.io.IOUtilities.streamToBytes(is);
String result = new String(data);
This will grab the input stream the HttpConnection object has gathered, use the RIM IOUtils class to nicely put it into an array then finally create a String from the data. It should be possible from their to use the JSON libraries that RIM include in their SDK to work on the JSON.
Note: Not sure if the cast is required, btw this is untested code.
You should also note there are 3 different APIs which you can use to create a network connection on BlackBerry.
Using the Generic Connection Framework
The oldest methed (OS 5 below) is a basic J2ME implementation with additional transport descriptors appended to the end of the URL. It uses the J2ME GCF. A great explanation is given here, describing how to always reliably open a HTTPConnection.
Using the Network API
Introduced in OS 5 and above. This is the current method you are using. It wraps over the nasty descriptor Strings that are added to the end of the URL in the GCF through the use of the ConnectionFactory and ConnectionDescriptor classes.
Using the Communications API
Introduced into OS 6 and above. This is the newest possible method, it is an even higher abstraction on the Network API. These API's abstract how the actual data is gathered and try to not bother you with the details of the protocol. The useful thing about this API is you just get the resulting data and don't have to worry about the implementation details.
You should note that as you are working with JSON it even will wrap around the details of converting the resulting data and convert it into the format you wanted. An example is shown here.

Resources