good morning, I have a solution in .net where I call the webservices of saber bargain finder max. Now I want to download the compressed information but the response object returns null. I read that you have to call the interface IClientMessageInspector BeforeSendRequest and AfterReceiveReply but I do not know how to proceed. someone will have an example or solution about it? Thank you
The response for the service cannot handle the compressed response, so yes, you have to put middleware in order to process the decompression before you let it continue.
First of all, you need to import the BFM WSDL as a service instead of as a web services, so:
Right click on "Service References" and click on "Add Service Reference..."
Paste the WSDL URL under "Address:" and click on "Go"
Recommendation: Download the WSDL and the associated schemas so you can modify them, since .NET has some issues handling some things, which you can manually modify. Sabre has some covered here.
Name the service whatever you like, in this example I'll call it BargainFinderMaxRQ_4_1_0_Srvc, under "Namespace:" and click on "OK"
Then, I created 2 classes, one that will be the one calling BFM ("BFM_v410Service"), and another one for the middleware ("BFMInspector").
Let's start with the BFMInspector:
// The inspector class has to implement both IClientMessageInspector and IEndpointBehavior interfaces
public class BFMInspector : IClientMessageInspector, IEndpointBehavior
{
// This is the method to action after receiving a response from Sabre
public void AfterReceiveReply(ref Message reply, object correlationState)
{
try
{
// Get compressed response from reply and load that into a byte array.
XmlDictionaryReader bodyReader = reply.GetReaderAtBodyContents();
bodyReader.ReadStartElement("CompressedResponse");
byte[] bodyByteArray = bodyReader.ReadContentAsBase64();
// Create some helper variables
StringBuilder uncompressed = new StringBuilder();
String xmlString = "";
XmlDocument xmlPayload = new XmlDocument();
// Load the byte array into memory
using (MemoryStream memoryStream = new MemoryStream(bodyByteArray))
{
// Unzip the Stream
using (GZipStream gZipStream = new GZipStream(memoryStream, CompressionMode.Decompress))
{
byte[] buffer = new byte[1024];
int readBytes;
// Unzips character by character
while ((readBytes = gZipStream.Read(buffer, 0, buffer.Length)) != 0)
{
for (int i = 0; i < readBytes; i++)
// Append all characters to build the response
uncompressed.Append((char)buffer[i]);
}
}
xmlString = uncompressed.ToString();
xmlString = xmlString.Replace("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>", "");
}
// Convert the string into an XML
xmlPayload.LoadXml(xmlString);
// Create a new Message, which is what will substitute what was returned by Sabre
Message tempMessage = Message.CreateMessage(reply.Version, null, xmlPayload.ChildNodes[0]);
tempMessage.Headers.CopyHeadersFrom(reply.Headers);
tempMessage.Properties.CopyProperties(reply.Properties);
MessageBuffer bufferOfFault = tempMessage.CreateBufferedCopy(Int32.MaxValue);
// Replace the reply with the new Message
reply = bufferOfFault.CreateMessage();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
public object BeforeSendRequest(ref Message request, IClientChannel channel)
{
// Nothing is done here, so we simply return null
return null;
}
public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
// Nothing done
}
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
// Add "this" as an endpoint to be inspected
clientRuntime.MessageInspectors.Add(this);
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
// Nothing done
}
public void Validate(ServiceEndpoint endpoint)
{
// Nothing done
}
}
Now, the BFM_v410Service:
// BFM calling class
public class BFM_v410Service
{
// The constructor and CreateRequest simeply create a complete request
private BargainFinderMaxRQRequest service;
private OTA_AirLowFareSearchRQ request;
public OTA_AirLowFareSearchRS response;
private string endpoint;
public BFM_v410Service(string token, string pcc, string convId, string endpoint)
{
CreateRequest(pcc, true);
this.endpoint = endpoint;
service = new BargainFinderMaxRQRequest()
{
MessageHeader = new BargainFinderMaxRQ_3_4_0_Srvc.MessageHeader()
{
From = new From()
{
PartyId = new PartyId[]
{
new PartyId()
{
Value = pcc
}
}
},
To = new To()
{
PartyId = new PartyId[]
{
new PartyId()
{
Value = endpoint
}
}
},
ConversationId = convId,
CPAId = pcc,
Service = new Service()
{
Value = "BargainFinderMaxRQ"
},
Action = "BargainFinderMaxRQ",
MessageData = new MessageData()
{
Timestamp = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ssK")
}
},
OTA_AirLowFareSearchRQ = request,
Security = new Security()
{
BinarySecurityToken = token
}
};
}
private void CreateRequest(string pcc, bool compressed)
{
request = new OTA_AirLowFareSearchRQ()
{
Version = "3.4.0",
POS = new SourceType[]
{
new SourceType()
{
PseudoCityCode = pcc,
RequestorID = new UniqueID_Type()
{
ID = "1",
Type = "1",
CompanyName = new CompanyNameType()
{
Code = "TN",
Value = "TN"
}
}
}
},
OriginDestinationInformation = new OTA_AirLowFareSearchRQOriginDestinationInformation[]
{
new OTA_AirLowFareSearchRQOriginDestinationInformation()
{
RPH = "1",
Item = "2018-09-21T11:00:00",
ItemElementName = ItemChoiceType.DepartureDateTime,
OriginLocation = new OriginDestinationInformationTypeOriginLocation()
{
LocationCode = "MVD"
},
DestinationLocation = new OriginDestinationInformationTypeDestinationLocation()
{
LocationCode = "KRK"
}
},
new OTA_AirLowFareSearchRQOriginDestinationInformation()
{
RPH = "2",
Item = "2018-09-28T11:00:00",
ItemElementName = ItemChoiceType.DepartureDateTime,
OriginLocation = new OriginDestinationInformationTypeOriginLocation()
{
LocationCode = "KRK"
},
DestinationLocation = new OriginDestinationInformationTypeDestinationLocation()
{
LocationCode = "MVD"
}
}
},
TravelerInfoSummary = new TravelerInfoSummaryType()
{
AirTravelerAvail = new TravelerInformationType[]
{
new TravelerInformationType()
{
PassengerTypeQuantity = new PassengerTypeQuantityType[]
{
new PassengerTypeQuantityType()
{
Code = "ADT",
Quantity = "1"
}
}
}
}
},
TPA_Extensions = new OTA_AirLowFareSearchRQTPA_Extensions()
{
IntelliSellTransaction = new TransactionType()
{
RequestType = new TransactionTypeRequestType()
{
Name = "50ITINS"
},
CompressResponse = new TransactionTypeCompressResponse()
{
Value = compressed
}
}
}
};
}
public void Execute()
{
try
{
// Instanciate the Inspector
BFMInspector inspector = new BFMInspector();
// Select the URL you'll be sending the request. I've passed this as a parameter in the constructor
EndpointAddress url = new EndpointAddress(new Uri(endpoint));
// Create a binding, with a couple of characteristics, because of the size of the response
Binding binding = new BasicHttpsBinding()
{
MaxReceivedMessageSize = Int32.MaxValue,
MaxBufferSize = Int32.MaxValue
};
// Create the executable the BargainFinderMaxPortTypeClient variable, which will allow me to call the service
BargainFinderMaxPortTypeClient execute = new BargainFinderMaxPortTypeClient(binding, url);
// Add the middleware. Here's where ApplyClientBehavior is called behind the scene and adds itself
execute.Endpoint.EndpointBehaviors.Add(inspector);
// Call BFM and successfully get the response as an OTA_AirLowFareSearchRS object
response = execute.BargainFinderMaxRQ(ref service.MessageHeader, ref service.Security, request);
Console.WriteLine(response);
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
Then, simply call this from a console application:
static void Main(string[] args)
{
System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls12;
string token = #"Shared/IDL:IceSess\/SessMgr:1\.0.IDL/Common/!ICESMS\/RESA!ICESMSLB\/RES.LB!-3146624380791354996!413892!0!1!E2E-1";
string pcc = "XXXX";
string convId = "HERE GOES YOUR CONVERSATION ID";
string endpoint = "https://webservices.havail.sabre.com";
BFM_v410Service bfm340 = new BFM_v410Service(token, pcc, convId, endpoint);
bfm410.Execute();
}
Hope this helps!
Related
Using c# with the .net framework and microsoft azure and i am trying to upload a file in a cli which should be picked up by a webjob. I'm sure the webjob is fine but i am having problems getting upload to work.
// Pick URL location of service up from metadata
AudioSamples client = new AudioSamples(new AnonymousCredential());
var id = Console.ReadLine();
Console.WriteLine();
string path = "api/samples/" + id;
Console.WriteLine("Enter the file name.");
string fileName = Console.ReadLine();
using (var stream = File.OpenRead(fileName))
{
HttpOperationResponse response = await client.PutAsync(path, new StreamContent(stream));
}
From what i understand the PutAsync should work for streaming the file but it gives me an error saying the command doesn't exist
this api should also be used with the upload to a blob but im not sure how it connect it to the client.
namespace AudioSamples.Controllers
{
[ApiExplorerSettings(IgnoreApi = true)]
public class DataController : ApiController
{
private const String partitionName = "AudioSamples_Partition_1";
private CloudStorageAccount storageAccount;
private CloudTableClient tableClient;
private CloudTable table;
private BlobStorageService _blobStorageService = new BlobStorageService();
private CloudQueueService _queueStorageService = new CloudQueueService();
String name;
public DataController()
{
storageAccount = CloudStorageAccount.Parse(ConfigurationManager.ConnectionStrings["AzureWebJobsStorage"].ToString());
tableClient = storageAccount.CreateCloudTableClient();
table = tableClient.GetTableReference("AudioSamples");
}
private void deleteOldBlobs(AudioSampleEntityModel sample)
{
CloudBlobContainer blobContainer = _blobStorageService.getCloudBlobContainer();
CloudBlockBlob blob;
if (sample.Blob != null)
{
blob = blobContainer.GetBlockBlobReference(sample.Blob);
blob.Delete();
}
if (sample.SampleBlob != null)
{
blob = blobContainer.GetBlockBlobReference(sample.SampleBlob);
blob.Delete();
}
}
// PUT: api/Data/5
public IHttpActionResult Put(String id)
{
// PUT – see also ProductsController.cs from Lab 4
// Create a retrieve operation.
// id is a parameter of method and forms the row key
TableOperation retrieveOperation =
TableOperation.Retrieve<AudioSampleEntityModel>(partitionName, id);
TableResult getOperationResult = table.Execute(retrieveOperation);
if (getOperationResult.Result == null)
return NotFound();
AudioSampleEntityModel sample = (AudioSampleEntityModel)getOperationResult.Result;
deleteOldBlobs(sample);
try
{
CloudBlobContainer blobContainer = _blobStorageService.getCloudBlobContainer();
name = string.Format("{0}{1}", Guid.NewGuid(), ".mp3");
String path = "/mp3s" + name;
var baseUrl = Request.RequestUri.GetLeftPart(UriPartial.Authority);
String sampleURL = baseUrl.ToString() + "/api/data/" + id;
sample.SampleBlobURL = sampleURL;
sample.Blob = path;
sample.CreatedDate = DateTime.Now;
sample.SampleDate = null;
var updateOperation = TableOperation.InsertOrReplace(sample);
table.Execute(updateOperation);
CloudBlockBlob blob = blobContainer.GetBlockBlobReference(sample.Blob);
var request = HttpContext.Current.Request;
blob.Properties.ContentType = "audio/mpeg3";
blob.UploadFromStream(request.InputStream);
}
catch (Exception e)
{
System.Diagnostics.Trace.WriteLine("DataController(PUT): " + e.Message);
return BadRequest("DataController(PUT): " + e.Message);
}
try
{
CloudQueue sampleQueue = _queueStorageService.getCloudQueue();
var queueMessageSample = new AudioSampleEntityModel(partitionName, id);
sampleQueue.AddMessage(new CloudQueueMessage(JsonConvert.SerializeObject(queueMessageSample)));
}
catch (Exception e)
{
System.Diagnostics.Trace.WriteLine("DataController(PUT): " + e.Message);
return BadRequest("DataController(PUT): " + e.Message);
}
System.Diagnostics.Trace.WriteLine(String.Format("*** WebRole: Enqueued '{0}'", sample.Blob));
return StatusCode(HttpStatusCode.NoContent);
}
}
}
This is the webjob which i think is working fine.
public class Functions
{
public static void GenerateSample(
[QueueTrigger("audiosamplemaker")] AudioSampleEntityModel sampleInQueue,
[Table("Samples", "{PartitionKey}", "{RowKey}")] AudioSampleEntityModel sampleInTable,
[Blob("audiocollection/audio/{queueTrigger}")] CloudBlockBlob inputBlob,
[Blob("audiocollection/samples/{queueTrigger}")] CloudBlockBlob outputBlob, TextWriter logger,
[Table("Samples")] CloudTable tableBinding, TextWriter kek)
{
//use log.WriteLine() rather than Console.WriteLine() for trace output
logger.WriteLine("GenerateSample() started...");
logger.WriteLine("Input blob is: " + sampleInQueue);
// Open streams to blobs for reading and writing as appropriate.
// Pass references to application specific methods
using (Stream input = inputBlob.OpenRead())
using (Stream output = outputBlob.OpenWrite())
{
createSample(input, output, 20);
outputBlob.Properties.ContentType = "audio/mp3";
outputBlob.Metadata["Title"] = inputBlob.Metadata["Title"];
}
logger.WriteLine("GenerateSample() completed...");
}
private static void createSample(Stream input, Stream output, int duration)
{
using (var reader = new Mp3FileReader(input, wave => new NLayer.NAudioSupport.Mp3FrameDecompressor(wave)))
{
Mp3Frame frame;
frame = reader.ReadNextFrame();
int frameTimeLength = (int)(frame.SampleCount / (double)frame.SampleRate * 1000.0);
int framesRequired = (int)(duration / (double)frameTimeLength * 1000.0);
int frameNumber = 0;
while ((frame = reader.ReadNextFrame()) != null)
{
frameNumber++;
if (frameNumber <= framesRequired)
{
output.Write(frame.RawData, 0, frame.RawData.Length);
}
else break;
}
}
}
}
In your web api controller, the put method only has one parameter named ‘id’. But in your client, you also passed a stream content in put method.
So you couldn’t call web api method successfully. And for this stream content, you could set a string or model type in Put method instead of file stream.
According to your description, I suppose you want to pass data from client to web api, then read data from this file path in web Api and upload data to a blob.
I have created a sample demo to upload a myfile.txt to a Blob. Other data types are similar to this. You could refer to.
Code in Console:
Code in AudioSampleEntityModel class:
public class AudioSampleEntityModel : TableEntity
{
public AudioSampleEntityModel()
{
}
public AudioSampleEntityModel(string partitionName, string id)
{
}
public string id { get; set; }
public string Blob { get; set; }
public string SampleBlob { get; set; }
public string SampleBlobURL { get; set; }
public DateTime CreatedDate { get; set; }
public string SampleDate { get; set; }
}
Code in Function.cs:
public class Functions
{
/// <summary>
/// pass the content from Queue to Blob(The content is from myfile.txt)
/// </summary>
/// <param name="model"></param>
/// <param name="orderBlob"></param>
public static void MultipleOutput(
[QueueTrigger("myqueue2")] AudioSampleEntityModel model,
[Blob("orders/myfile")] out string orderBlob) //create a container named 'orders'
{
orderBlob = model.SampleBlob; //store the content from SampleBlob property to Blob
}
}
Code in Program:
class Program
{
static void Main() {
Console.WriteLine("----------------Update Employee -------------------");
Console.WriteLine("Enter id which you want to update");
string id = Console.ReadLine();
var response=DemoData(id).Result;
Console.WriteLine("the data from webapi: "+response);
var host = new JobHost();
// The following code ensures that the WebJob will be running continuously
host.RunAndBlock();
}
public static async Task<string> DemoData(string id)
{
HttpClient client = new HttpClient();
string path = "http://localhost:53581/api/values/" + id;
Console.WriteLine("Enter the file name.");
string fileName = Console.ReadLine();
string filepath = "E:\\JanleyZhang\\" + fileName;
var filepathJson = JsonConvert.SerializeObject(filepath);// convert other FileStream type to json string
var data = new StringContent(content: filepathJson,
encoding: Encoding.UTF8,
mediaType: "application/json");
var response = await client.PutAsync(path, data);//get response from web api
var content = response.Content;
var result = await content.ReadAsStringAsync();//read content from response
//upload the data to a queue
string connectionString = AmbientConnectionStringProvider.Instance.GetConnectionString(ConnectionStringNames.Storage);
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(connectionString);
CloudQueueClient queueClient = storageAccount.CreateCloudQueueClient();
CloudQueue queue = queueClient.GetQueueReference("myqueue2");
queue.CreateIfNotExists();
AudioSampleEntityModel model = new AudioSampleEntityModel()
{
id=id,
SampleBlob=result //pass the result to this property
};
queue.AddMessage(new CloudQueueMessage(JsonConvert.SerializeObject(model))); //store the file content to queue
return result;
}
}
Code in api controller:
public string Put(string id, [FromBody]string filepath) //pass two parameters
{
string b = "The id and model id are not equal.";
if (id == "1")
{
FileStream fs = File.OpenRead(filepath);
byte[] byt = new byte[fs.Length];
UTF8Encoding temp = new UTF8Encoding(true);
while (fs.Read(byt, 0, byt.Length) > 0)
{
b=temp.GetString(byt);//read the content from myfile.txt
// The operation about uploading a blob .........
}
return b;
}
return b;
}
You could see the result like this:
I am developing a ONVIF driver using .NET 4 (Windows Forms, not WCF).
I started importing WSDL files as a service in visual studio.
So I am able to send command to a device in this way:
HttpTransportBindingElement httpTransportBindingElement = new HttpTransportBindingElement();
[...]
TextMessageEncodingBindingElement messegeElement = new TextMessageEncodingBindingElement();
[...]
CustomBinding binding = new CustomBinding(messegeElement, httpTransportBindingElement);
[...]
EndpointAddress serviceAddress = new EndpointAddress(url);
DeviceClient deviceClient = new DeviceClient(binding, serviceAddress);
Device channel = deviceClient.ChannelFactory.CreateChannel();
DeviceServiceCapabilities dsc = channel.GetServiceCapabilities();
But I am not able to manage HTTP digest authentication. I spent days searching on google examples and solutions, but the only ways seems to be hand write XML code. There is not any clean solution like:
deviceClient.ChannelFactory.Credentials.HttpDigest.ClientCredential.UserName = USERNAME;
deviceClient.ChannelFactory.Credentials.HttpDigest.ClientCredential.Password = digestPassword;
(that doesn't work)?
First of all you should install Microsoft.Web.Services3 package. (View> Other windows> Package manager console). Then you must add digest behavior to your endpoint. The first part of the code is PasswordDigestBehavior class and after that it is used for connecting to an ONVIF device service.
public class PasswordDigestBehavior : IEndpointBehavior
{
public String Username { get; set; }
public String Password { get; set; }
public PasswordDigestBehavior(String username, String password)
{
this.Username = username;
this.Password = password;
}
public void AddBindingParameters(ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
{
// do nothing
}
public void ApplyClientBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime)
{
//clientRuntime.MessageInspectors.Add(new PasswordDigestMessageInspector(this.Username, this.Password));
clientRuntime.MessageInspectors.Add(new PasswordDigestMessageInspector(this.Username, this.Password));
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher)
{
throw new NotImplementedException();
}
public void Validate(ServiceEndpoint endpoint)
{
// do nothing...
}
}
public class PasswordDigestMessageInspector : IClientMessageInspector
{
public String Username { get; set; }
public String Password { get; set; }
public PasswordDigestMessageInspector(String username, String password)
{
this.Username = username;
this.Password = password;
}
public void AfterReceiveReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
{
// do nothing
}
public object BeforeSendRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel)
{
// Use the WSE 3.0 security token class
var option = PasswordOption.SendHashed;
if (string.IsNullOrEmpty(Username) || string.IsNullOrEmpty(Password))
option = PasswordOption.SendPlainText;
UsernameToken token = new UsernameToken(this.Username, this.Password, option);
// Serialize the token to XML
XmlDocument xmlDoc = new XmlDocument();
XmlElement securityToken = token.GetXml(xmlDoc);
// find nonce and add EncodingType attribute for BSP compliance
XmlNamespaceManager nsMgr = new XmlNamespaceManager(xmlDoc.NameTable);
nsMgr.AddNamespace("wsse", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
XmlNodeList nonces = securityToken.SelectNodes("//wsse:Nonce", nsMgr);
XmlAttribute encodingAttr = xmlDoc.CreateAttribute("EncodingType");
encodingAttr.Value = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary";
if (nonces.Count > 0)
{
nonces[0].Attributes.Append(encodingAttr);
//nonces[0].Attributes[0].Value = "foo";
}
//
MessageHeader securityHeader = MessageHeader.CreateHeader("Security", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", securityToken, false);
request.Headers.Add(securityHeader);
// complete
return Convert.DBNull;
}
}
And this is how to use it:
var endPointAddress = new EndpointAddress("http://DEVICE_IPADDRESS/onvif/device_service");
var httpTransportBinding = new HttpTransportBindingElement { AuthenticationScheme = AuthenticationSchemes.Digest };
var textMessageEncodingBinding = new TextMessageEncodingBindingElement { MessageVersion = MessageVersion.CreateVersion(EnvelopeVersion.Soap12, AddressingVersion.None) };
var customBinding = new CustomBinding(textMessageEncodingBinding, httpTransportBinding);
var passwordDigestBehavior = new PasswordDigestBehavior(USERNAME, PASSWORD);
var deviceService = new DeviceClient(customBinding, endPointAddress);
deviceService.Endpoint.Behaviors.Add(passwordDigestBehavior);
For future readers, finally I was able to perform both type of authentication without using WSE 3.0.
This is partial code (for shortness), based on the IClientMessageInspector interface (you can find lot of other examples based on this interface):
public object BeforeSendRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel)
{
if (HTTPDigestAuthentication)
{
string digestHeader = string.Format("Digest username=\"{0}\",realm=\"{1}\",nonce=\"{2}\",uri=\"{3}\"," +
"cnonce=\"{4}\",nc={5:00000000},qop={6},response=\"{7}\",opaque=\"{8}\"",
_username, realm, nonce, new Uri(this.URI).AbsolutePath, cnonce, counter, qop, digestResponse, opaque);
HttpRequestMessageProperty httpRequest = new HttpRequestMessageProperty();
httpRequest.Headers.Add("Authorization", digestHeader);
request.Properties.Add(HttpRequestMessageProperty.Name, httpRequest);
return Convert.DBNull;
}
else if (UsernametokenAuthorization)
{
string headerText = "<wsse:UsernameToken xmlns:wsse=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\" xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\">" +
"<wsse:Username>" + _username + "</wsse:Username>" +
"<wsse:Password Type=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest\">" + digestPassword + "</wsse:Password>" +
"<wsse:Nonce EncodingType=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary\">" + Convert.ToBase64String(nonce) + "</wsse:Nonce>" +
"<wsu:Created xmlns=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\">" + created + "</wsu:Created>" +
"</wsse:UsernameToken>";
XmlDocument MyDoc = new XmlDocument();
MyDoc.LoadXml(headerText);
MessageHeader myHeader = MessageHeader.CreateHeader("Security", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", MyDoc.DocumentElement, false);
request.Headers.Add(myHeader);
return Convert.DBNull;
}
return request;
}
This class should be able to replace the WSE UserNameToken object and remove the dependency on WSE. It also makes the searching and repairing nonces in IClientInspector unnecessary. I've only tested it on 1 camera and only with hashed passwords. YMMV.
public enum PasswordOption
{
SendPlain = 0,
SendHashed = 1,
SendNone = 2
}
public class UsernameToken
{
private string Username;
private string Password;
private PasswordOption PwdOption;
public UsernameToken(string username, string password, PasswordOption option)
{
Username = username;
Password = password;
PwdOption = option;
}
public XmlElement GetXml(XmlDocument xmlDoc)
{
string wsse = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";
string wsu = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd";
XmlDocument doc = xmlDoc;
//XmlElement securityEl = doc.CreateElement("Security", wsse);
XmlElement usernameTokenEl = doc.CreateElement("wsse", "UsernameToken", wsse);
XmlAttribute a = doc.CreateAttribute("wsu", "Id", wsu);
usernameTokenEl.SetAttribute("xmlns:wsse", wsse);
usernameTokenEl.SetAttribute("xmlns:wsu", wsu);
a.InnerText = "SecurityToken-" + Guid.NewGuid().ToString();
usernameTokenEl.Attributes.Append(a);
//Username
XmlElement usernameEl = doc.CreateElement("wsse:Username", wsse);
usernameEl.InnerText = Username;
usernameTokenEl.AppendChild(usernameEl);
//Password
XmlElement pwdEl = doc.CreateElement("wsse:Password", wsse);
switch (PwdOption)
{
case PasswordOption.SendHashed:
//Nonce+Create+Password
pwdEl.SetAttribute("Type", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest");
string created = DateTime.Now.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ");
byte[] nonce = GenerateNonce(16);
byte[] pwdBytes = Encoding.ASCII.GetBytes(Password);
byte[] createdBytes = Encoding.ASCII.GetBytes(created);
byte[] pwdDigest = new byte[nonce.Length + pwdBytes.Length + createdBytes.Length];
Array.Copy(nonce, pwdDigest, nonce.Length);
Array.Copy(createdBytes, 0, pwdDigest, nonce.Length, createdBytes.Length);
Array.Copy(pwdBytes, 0, pwdDigest, nonce.Length + createdBytes.Length, pwdBytes.Length);
pwdEl.InnerText = ToBase64(SHA1Hash(pwdDigest));
usernameTokenEl.AppendChild(pwdEl);
//Nonce
XmlElement nonceEl = doc.CreateElement("wsse:Nonce", wsse);
nonceEl.SetAttribute("EncodingType", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary");
nonceEl.InnerText = ToBase64(nonce);
usernameTokenEl.AppendChild(nonceEl);
//Created
XmlElement createdEl = doc.CreateElement("wsu:Created", wsu);
createdEl.InnerText = created;
usernameTokenEl.AppendChild(createdEl);
break;
case PasswordOption.SendNone:
pwdEl.SetAttribute("Type", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText");
pwdEl.InnerText = "";
usernameTokenEl.AppendChild(pwdEl);
break;
case PasswordOption.SendPlain:
pwdEl.SetAttribute("Type", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText");
pwdEl.InnerText = Password;
usernameTokenEl.AppendChild(pwdEl);
break;
}
return usernameTokenEl;
}
private byte[] GenerateNonce(int bytes)
{
byte[] output = new byte[bytes];
Random r = new Random(DateTime.Now.Millisecond);
r.NextBytes(output);
return output;
}
private static byte[] SHA1Hash(byte[] input)
{
SHA1CryptoServiceProvider sha1Hasher = new SHA1CryptoServiceProvider();
return sha1Hasher.ComputeHash(input);
}
private static string ToBase64(byte[] input)
{
return Convert.ToBase64String(input);
}
}
}
i need an advice about how to return an error message caught on server to client. I am creating WCF Restfull service and able to returning an error message while using GET method. But hardly find the proper way to return error message from POST method.
EDITED
For #Abd:
I have tried using throw WebFaultException, like below code:
try
{
newbudgetid = _service.Create(budgettrx);
}
catch (Exception ex)
{
error_message = ex.Message;
MyCustomErrorDetail customerror = new MyCustomErrorDetail(
"Error", error_message);
throw new WebFaultException<MyCustomErrorDetail>(customerror, HttpStatusCode.NotFound);
}
And this is the class definition:
public class MyCustomErrorDetail
{
public MyCustomErrorDetail(string errorInfo, string errorDetails)
{
ErrorInfo = errorInfo;
ErrorDetails = errorDetails;
}
[DataMember]
public string ErrorInfo { get; private set; }
[DataMember]
public string ErrorDetails { get; private set; }
}
On client code, how should i write the error output from server ?
BudgetTransactionRequest bt = new BudgetTransactionRequest
{
transaction_code = "7PRM007690 ",
category = "Expenses",
claim_status = "Presales ID",
amount = "320000.00000",
application_type = "Payment Request",
opportunity = "BSMD000586",
project = null,
request_date = new DateTime(2013, 03, 09),
request_status = "Validated",
owner = "nurul.wiiyanti",
};
WebClient proxy = new WebClient();
proxy.Headers["Content-Type"] = "application/json";
MemoryStream ms = new MemoryStream();
DataContractJsonSerializer serialize = new DataContractJsonSerializer(typeof(BudgetTransactionRequest));
serialize.WriteObject(ms, bt);
byte[] data = proxy.UploadData("http://10.10.64.19:8082/Service1.svc/CreateBudgetTransaction/", "POST", ms.ToArray());
Stream stream = new MemoryStream(data);
DataContractJsonSerializer obj = new DataContractJsonSerializer(typeof(BudgetTransactionRequest));
You can create a ServiceResult class and use it for all Get and Post methods. In this class you can use properties such as Generic Result, HasException, ExceptionMessage etc.
throw a WebFaultException(T errorDetail, HttpResponseCode code)
Here you set your response type to another object type, which makes sense, and also you set the ResponseCode that you want.
The errorDetail must be serializable
this link could be useful, or this link
Iam using CefSharp's SchemeHandler in order to grab resources from my C# project like .css, .js or .png files using a custom url for example custom://cefsharp/assets/css/style.css
I've 2 custom classes in order to archive this.
First class, MyCustomSchemeHandlerFactory will be the one that handles the custom Scheme and it looks like this, where "custom" will be the custom scheme:
internal class MyCustomSchemeHandlerFactory : ISchemeHandlerFactory
{
public const string SchemeName = "custom";
public IResourceHandler Create(IBrowser browser, IFrame frame, string schemeName, IRequest request)
{
return new MyCustomSchemeHandler();
}
}
The next class I've implemented is MyCustomSchemeHandler which will receive the call and output a response and it looks like this:
internal class MyCustomSchemeHandler : IResourceHandler
{
private static readonly IDictionary<string, string> ResourceDictionary;
private string mimeType;
private MemoryStream stream;
static MyCustomSchemeHandler()
{
ResourceDictionary = new Dictionary<string, string>
{
{ "/home.html", Properties.Resources.index},
{ "/assets/css/style.css", Properties.Resources.style}
};
}
public Stream Stream { get; set; }
public int StatusCode { get; set; }
public string StatusText { get; set; }
public string MimeType { get; set; }
public NameValueCollection Headers { get; private set; }
public Stream GetResponse(IResponse response, out long responseLength, out string redirectUrl)
{
redirectUrl = null;
responseLength = -1;
response.MimeType = MimeType;
response.StatusCode = StatusCode;
response.StatusText = StatusText;
response.ResponseHeaders = Headers;
var memoryStream = Stream as MemoryStream;
if (memoryStream != null)
{
responseLength = memoryStream.Length;
}
return Stream;
}
public bool ProcessRequestAsync(IRequest request, ICallback callback)
{
// The 'host' portion is entirely ignored by this scheme handler.
var uri = new Uri(request.Url);
var fileName = uri.AbsolutePath;
string resource;
if (ResourceDictionary.TryGetValue(fileName, out resource) && !string.IsNullOrEmpty(resource))
{
var resourceHandler = ResourceHandler.FromString(resource);
stream = (MemoryStream)resourceHandler.Stream;
var fileExtension = Path.GetExtension(fileName);
mimeType = ResourceHandler.GetMimeType(fileExtension);
callback.Continue();
return true;
}
else
{
callback.Dispose();
}
return false;
}
void GetResponseHeaders(IResponse response, out long responseLength, out string redirectUrl)
{
responseLength = stream == null ? 0 : stream.Length;
redirectUrl = null;
response.StatusCode = (int)HttpStatusCode.OK;
response.StatusText = "OK";
response.MimeType = mimeType;
}
bool ReadResponse(Stream dataOut, out int bytesRead, ICallback callback)
{
//Dispose the callback as it's an unmanaged resource, we don't need it in this case
callback.Dispose();
if (stream == null)
{
bytesRead = 0;
return false;
}
//Data out represents an underlying buffer (typically 32kb in size).
var buffer = new byte[dataOut.Length];
bytesRead = stream.Read(buffer, 0, buffer.Length);
dataOut.Write(buffer, 0, buffer.Length);
return bytesRead > 0;
}
bool CanGetCookie(Cookie cookie)
{
return true;
}
bool CanSetCookie(Cookie cookie)
{
return true;
}
void Cancel()
{
}
}
Inside this class I've defined a custom resource dictionary which will dictate what file from the resources will be used, so as I stated in the first example, custom://cefsharp/assets/css/style.css should load the resource Properties.Resources.style, the problem is that nothing gets loaded once I enter to the specific url, I've tried to output the mimeType and It works but somehow the file itself won't output correctly. Is there something wrong with my implementation?
Additionaly I've tried to output the raw file in the form of:
if (ResourceDictionary.TryGetValue(fileName, out resource) && !string.IsNullOrEmpty(resource))
{
MessageBox.Show(resource);
}
And it outputs the correct file without any problems.
To load the custom Scheme I use the following code before initializing CefSharp:
var settings = new CefSettings();
settings.RegisterScheme(new CefCustomScheme
{
SchemeName = MyCustomSchemeHandlerFactory.SchemeName,
SchemeHandlerFactory = new MyCustomSchemeHandlerFactory()
});
The above classes were based on the following links:
MyCustomSchemeHandlerFactory: FlashResourceHandlerFactory.cs
MyCustomSchemeHandler: CefSharpSchemeHandler.cs and ResourceHandler.cs
Since Cefsharp changed a bit in last few months here is an updated and easier way of handling 'file' protocol. I wrote blog post on this matter.
What you want to add is your scheme handler and its factory:
using System;
using System.IO;
using CefSharp;
namespace MyProject.CustomProtocol
{
public class CustomProtocolSchemeHandler : ResourceHandler
{
// Specifies where you bundled app resides.
// Basically path to your index.html
private string frontendFolderPath;
public CustomProtocolSchemeHandler()
{
frontendFolderPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "./bundle/");
}
// Process request and craft response.
public override bool ProcessRequestAsync(IRequest request, ICallback callback)
{
var uri = new Uri(request.Url);
var fileName = uri.AbsolutePath;
var requestedFilePath = frontendFolderPath + fileName;
if (File.Exists(requestedFilePath))
{
byte[] bytes = File.ReadAllBytes(requestedFilePath);
Stream = new MemoryStream(bytes);
var fileExtension = Path.GetExtension(fileName);
MimeType = GetMimeType(fileExtension);
callback.Continue();
return true;
}
callback.Dispose();
return false;
}
}
public class CustomProtocolSchemeHandlerFactory : ISchemeHandlerFactory
{
public const string SchemeName = "customFileProtocol";
public IResourceHandler Create(IBrowser browser, IFrame frame, string schemeName, IRequest request)
{
return new CustomProtocolSchemeHandler();
}
}
}
And then register it before calling Cef.Initialize:
var settings = new CefSettings
{
BrowserSubprocessPath = GetCefExecutablePath()
};
settings.RegisterScheme(new CefCustomScheme
{
SchemeName = CustomProtocolSchemeHandlerFactory.SchemeName,
SchemeHandlerFactory = new CustomProtocolSchemeHandlerFactory()
});
If you simply need to return a string, then you can use ResourceHandler.FromString(html, mimeType). For this you just need to implement the ISchemeHandlerFactory.
https://github.com/cefsharp/CefSharp/blob/cefsharp/47/CefSharp/ResourceHandler.cs#L98
Example reading from a file https://github.com/cefsharp/CefSharp/blob/cefsharp/47/CefSharp.Example/CefSharpSchemeHandlerFactory.cs#L17 which can be translated to reading from a string quite simply.
I have small program that takes the links from a text file, pass those links to backend system at ImportIO, and save the results to a CSV. However I am seeing following errors after 15,20 min of run. I encounter two exception whichever comes first
1. System.OutOfMemoryException
OR
2. System.NUllReferenceException
Both of these are however I feel my fault somewhere in the code. I am not an expert but I tried to use timer, or closing the files, or even setting objects to null. None worked or even using ArgumentNullException.
I ran the code analysis and it suggested that I should Idispose by this error.
CA1001 Types that own disposable fields should be disposable Implement
IDisposable on 'ImportIO' because it creates members of the following
IDisposable types: 'BlockingCollection>'. Ostock Main.cs 232
My code is as followed, I am not including importIO class it is long. I think solution is easy but I am just not on right path. Could you guys please help?
namespace MinimalCometLibrary
{
class Program
{
private static CountdownEvent countdownLatch;
static void Main(string[] args)
{
string[] lines = File.ReadAllLines(#"C:\Users\James\Desktop\Exper\Input_Links\Stock_links.txt");
for (int i = 0; i < lines.Length; i++)
{
string[] line = lines[i].Split(new string[] { "\t" }, StringSplitOptions.RemoveEmptyEntries);
for (int j = 0; j < line.Length; j++)
{
ImportIO io = new ImportIO("https://query.import.io", Guid.Parse("sdasd-asdasd-NoReal-3easdecb"), "NoReal=");
/* Time Starts
Stopwatch sw = new Stopwatch(); // sw cotructor
sw.Start(); // starts the stopwatch
for (int b = 0; ; b++)
{
if (b % 1000 == 0) // if in 100000th iteration (could be any other large number
// depending on how often you want the time to be checked)
{
sw.Stop(); // stop the time measurement
if (sw.ElapsedMilliseconds > 25) // check if desired period of time has elapsed
{
break; // if more than 5000 milliseconds have passed, stop looping and return
// to the existing code
}
else
{
sw.Start(); // if less than 5000 milliseconds have elapsed, continue looping
// and resume time measurement
}
}
}
//Time Ends
*/
io.Connect();
countdownLatch = new CountdownEvent(1);
// Query for tile SamsClub_Extractor, line[j]
Dictionary<String, Object> query1 = new Dictionary<string, object>();
query1.Add("input", new Dictionary<String, String>() { { "webpage/url", line[j] } });
query1.Add("connectorGuids", new List<String>() { "189f34f3-0f82-4abb-8fbc-f353f35a255a" });
io.DoQuery(query1, HandleQuery);
countdownLatch.Wait();
io.Disconnect();
}
}
Environment.Exit(0);
}
private static void HandleQuery(Query query, Dictionary<String, Object> message)
{
if (message["type"].Equals("MESSAGE"))
{
Console.WriteLine("Got data!");
string JSON = JsonConvert.SerializeObject(message["data"]);
//Deserialize to strongly typed class i.e., RootObject
RootObject obj = JsonConvert.DeserializeObject<RootObject>(JSON);
// handle null reference
if (obj == null) { throw new ArgumentNullException("PleaseKeepRunning"); }
//loop through the list and write to CSV file
foreach (Result resultsItem in obj.results)
{
Console.WriteLine(resultsItem.itemnbr + "-" + resultsItem.price +
"-" + resultsItem.product_name + "_" + obj.pageUrl);
string filePath = #"C:\Users\James\Desktop\Exper\Output_Files\StockPrice_NOW.txt";
//checking if file already exists, if not, create it:
if (!File.Exists(filePath))
{
FileStream fs = new FileStream(filePath, FileMode.CreateNew);
fs.Close();
}
//writing to a file (appending text):
using (FileStream fs = new FileStream(filePath, FileMode.Append, FileAccess.Write))
{
using (TextWriter tw = new StreamWriter(fs))
tw.WriteLine(resultsItem.itemnbr + "\t" + resultsItem.price + "\t" + resultsItem.product_name + "\t" + resultsItem.misc +
"\t" + resultsItem.qty + "\t" + obj.pageUrl);
fs.Close();
}
//Set object to null
obj = null;
obj.results = null;
}
}
if (query.isFinished) countdownLatch.Signal();
}
}
//root Object
public class Result
{
public double price { get; set; }
public string itemnbr { get; set; }
public string product_name { get; set; }
public string qty { get; set; }
public string misc { get; set; }
}
public class RootObject
{
public List<string> cookies { get; set; }
public List<Result> results { get; set; }
public string pageUrl { get; set; }
public string connectorGuid { get; set; }
public string connectorVersionGuid { get; set; }
public int offset { get; set; }
}
Please excuse my limited knowledge in .net. I am totally new to it. :)
Thanks
---- Edit
I used dispose and using as suggested but I am still facing the error. I am seeing error exception and debugger highlight this code of line in importIO.
new Thread(new ThreadStart(PollQueue)).Start();
I also observe that stock.vshost.exe *32 also keep increasing memory and throw out of memory exception at any time after 70MB or something. I am including the importIO class code
class ImportIO
{
private String host { get; set; }
private int port { get; set; }
private Guid userGuid;
private String apiKey;
private static String messagingChannel = "/messaging";
private String url;
private int msgId = 0;
private String clientId;
private Boolean isConnected;
CookieContainer cookieContainer = new CookieContainer();
Dictionary<Guid, Query> queries = new Dictionary<Guid, Query>();
private BlockingCollection<Dictionary<String, Object>> messageQueue = new BlockingCollection<Dictionary<string, object>>();
public ImportIO(String host = "http://query.import.io", Guid userGuid = default(Guid), String apiKey = null)
{
this.userGuid = userGuid;
this.apiKey = apiKey;
this.url = host + "/query/comet/";
clientId = null;
}
public void Login(String username, String password, String host = "http://api.import.io")
{
Console.WriteLine("Logging in");
String loginParams = "username=" + HttpUtility.UrlEncode(username) + "&password=" + HttpUtility.UrlEncode(password);
String searchUrl = host + "/auth/login";
HttpWebRequest loginRequest = (HttpWebRequest)WebRequest.Create(searchUrl);
loginRequest.Method = "POST";
loginRequest.ContentType = "application/x-www-form-urlencoded";
loginRequest.ContentLength = loginParams.Length;
loginRequest.CookieContainer = cookieContainer;
using (Stream dataStream = loginRequest.GetRequestStream())
{
dataStream.Write(System.Text.UTF8Encoding.UTF8.GetBytes(loginParams), 0, loginParams.Length);
HttpWebResponse loginResponse = (HttpWebResponse)loginRequest.GetResponse();
if (loginResponse.StatusCode != HttpStatusCode.OK)
{
throw new Exception("Could not log in, code:" + loginResponse.StatusCode);
}
else
{
foreach (Cookie cookie in loginResponse.Cookies)
{
if (cookie.Name.Equals("AUTH"))
{
// Login was successful
Console.WriteLine("Login Successful");
}
}
}
}
}
public List<Dictionary<String, Object>> Request(String channel, Dictionary<String, Object> data = null, String path = "", Boolean doThrow = true)
{
Dictionary<String, Object> dataPacket = new Dictionary<String, Object>();
dataPacket.Add("channel", channel);
dataPacket.Add("connectionType", "long-polling");
dataPacket.Add("id", (msgId++).ToString());
if (this.clientId != null)
dataPacket.Add("clientId", this.clientId);
if (data != null)
{
foreach (KeyValuePair<String, Object> entry in data)
{
dataPacket.Add(entry.Key, entry.Value);
}
}
String url = this.url + path;
if (apiKey != null)
{
url += "?_user=" + HttpUtility.UrlEncode(userGuid.ToString()) + "&_apikey=" + HttpUtility.UrlEncode(apiKey);
}
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.AutomaticDecompression = DecompressionMethods.GZip;
request.Method = "POST";
request.ContentType = "application/json;charset=UTF-8";
request.Headers.Add(HttpRequestHeader.AcceptEncoding, "gzip");
String dataJson = JsonConvert.SerializeObject(new List<Object>() { dataPacket });
request.ContentLength = dataJson.Length;
request.CookieContainer = cookieContainer;
using (Stream dataStream = request.GetRequestStream())
{
dataStream.Write(System.Text.UTF8Encoding.UTF8.GetBytes(dataJson), 0, dataJson.Length);
try
{
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
using (StreamReader responseStream = new StreamReader(response.GetResponseStream()))
{
String responseJson = responseStream.ReadToEnd();
List<Dictionary<String, Object>> responseList = JsonConvert.DeserializeObject<List<Dictionary<String, Object>>>(responseJson);
foreach (Dictionary<String, Object> responseDict in responseList)
{
if (responseDict.ContainsKey("successful") && (bool)responseDict["successful"] != true)
{
if (doThrow)
throw new Exception("Unsucessful request");
}
if (!responseDict["channel"].Equals(messagingChannel)) continue;
if (responseDict.ContainsKey("data"))
{
messageQueue.Add(((Newtonsoft.Json.Linq.JObject)responseDict["data"]).ToObject<Dictionary<String, Object>>());
}
}
return responseList;
}
}
catch (Exception e)
{
Console.WriteLine("Error occurred {0}", e.Message);
return new List<Dictionary<String, Object>>();
}
}
}
public void Handshake()
{
Dictionary<String, Object> handshakeData = new Dictionary<String, Object>();
handshakeData.Add("version", "1.0");
handshakeData.Add("minimumVersion", "0.9");
handshakeData.Add("supportedConnectionTypes", new List<String> { "long-polling" });
handshakeData.Add("advice", new Dictionary<String, int>() { { "timeout", 60000 }, { "interval", 0 } });
List<Dictionary<String, Object>> responseList = Request("/meta/handshake", handshakeData, "handshake");
clientId = (String)responseList[0]["clientId"];
}
public void Connect()
{
if (isConnected)
{
return;
}
Handshake();
Dictionary<String, Object> subscribeData = new Dictionary<string, object>();
subscribeData.Add("subscription", messagingChannel);
Request("/meta/subscribe", subscribeData);
isConnected = true;
new Thread(new ThreadStart(Poll)).Start();
new Thread(new ThreadStart(PollQueue)).Start();
}
public void Disconnect()
{
Request("/meta/disconnect", null, "", true);
isConnected = false;
}
private void Poll()
{
while (isConnected)
{
Request("/meta/connect", null, "connect", false);
}
}
private void PollQueue()
{
while (isConnected)
{
ProcessMessage(messageQueue.Take());
}
}
private void ProcessMessage(Dictionary<String, Object> data)
{
Guid requestId = Guid.Parse((String)data["requestId"]);
Query query = queries[requestId];
query.OnMessage(data);
if (query.isFinished)
{
queries.Remove(requestId);
}
}
public void DoQuery(Dictionary<String, Object> query, QueryHandler queryHandler)
{
Guid requestId = Guid.NewGuid();
queries.Add(requestId, new Query(query, queryHandler));
query.Add("requestId", requestId);
Request("/service/query", new Dictionary<String, Object>() { { "data", query } });
}
}
Try calling Dispose() method because as seen in your error message , it's a memory error because you keep opening files and reading them and then keeping the data there loaded on memory which causes the crash you see after some time
Try this :
if (!File.Exists(filePath))
{
FileStream fs = new FileStream(filePath, FileMode.CreateNew);
fs.Close();
fs.Dispose();
}
Also use the using() { } for the ImportIO class
using(ImportIO myIO = new ImportIO) { }
I can't say if your exceptions are related to it or not without seeing complete code, but the warning is about an issue "in" ImportIO, not in the code that's calling it (it's complaining that the ImportIO class does not implement IDisposable, not that you do something wrong with it)
Since you edited with the class : just implement IDisposable on your ImportIO class, here's a link on how to properly implement IDisposable : Implementing IDisposable correctly
Make sure to dispose of the BlockingCollection in the dispose of your ImportIO.
Then wrap your ImportIO in a using and the warning should go away. I'd be surprised if that alone caused those exceptions however but this is the way to fix your warning.