I would like to use Rx in my SL app. I want to set up an observable on my REST requests to my webserver. I dont see how to wire up Observable.FromEvent or Observable.FromAsync. My best guess is to make Webclient completion fire an event and then do Observable.FromEvent. IS there a better way?
Here you go, this is the best way to make a web request in Rx.
public IObservable<WebResponse> MakeWebRequest(
Uri uri,
Dictionary<string, string> headers = null,
string content = null,
int retries = 3,
TimeSpan? timeout = null)
{
var request = Observable.Defer(() =>
{
var hwr = WebRequest.Create(uri);
if (headers != null)
{
headers.ForEach(x => hwr.Headers[x.Key] = x.Value);
}
if (content == null)
{
return Observable.FromAsyncPattern<WebResponse>(hwr.BeginGetResponse, hwr.EndGetResponse)();
}
var buf = Encoding.UTF8.GetBytes(content);
return Observable.FromAsyncPattern<Stream>(hwr.BeginGetRequestStream, hwr.EndGetRequestStream)()
.SelectMany(x => Observable.FromAsyncPattern<byte[], int, int>(x.BeginWrite, x.EndWrite)(buf, 0, buf.Length))
.SelectMany(_ => Observable.FromAsyncPattern<WebResponse>(hwr.BeginGetResponse, hwr.EndGetResponse)());
});
return request.Timeout(timeout ?? TimeSpan.FromSeconds(15)).Retry(retries);
}
Here's how to use it:
MakeWebRequest(new Uri("http://www.google.com"))
.Subscribe(
x => Console.WriteLine("Response is {0}", x),
ex => Console.WriteLine("Someone Set Us Up The Bomb: {0}", ex.Message));
Related
I'm attempting it make a simple proxy server that will try to stream back data from an IP camera (the IP camera doesn't honor OPTIONS and has some other issues!). I tried doing this using NancyFX and Krestrel with the following proxy module. The idea was to just get 1028 bytes of data in and write it to the output stream asynchronously until canceled.
Here is a sample Nancy Module:
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading;
using System.Threading.Tasks;
using Nancy;
namespace Server.Modules
{
public class Proxy : NancyModule
{
public Proxy() : base("api/proxy")
{
Get("/", ProxyPage);
}
private async Task<Response> ProxyPage(dynamic args, CancellationToken cancellationToken)
{
// Create HttpClient
using (var httpClient = new HttpClient()) // Make this global/cached and indexed by auth code
{
// Handle Authentication
var auth = string.Empty;
if (!string.IsNullOrEmpty(Request.Headers.Authorization) && Request.Headers.Authorization.Contains(" "))
auth = Request.Headers.Authorization.Split(' ')[1];
else if (!string.IsNullOrEmpty(Request.Query.authorization))
auth = Request.Query.authorization;
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", auth);
// Create Proxy REsponse object
var proxyResponse = new Response();
// Get Async
HttpResponseMessage response = await httpClient.GetAsync(Request.Query["url"],
HttpCompletionOption.ResponseHeadersRead, cancellationToken);
// Set Content Type
proxyResponse.ContentType = response.Content.Headers.ContentType.ToString();
// Set Status Code
proxyResponse.StatusCode = (HttpStatusCode)(int)response.StatusCode;
// Handle stream writing
proxyResponse.Contents = async s =>
{
var result = response.Content.ReadAsStreamAsync();
var data = new byte[1028];
int bytesRead;
while (!cancellationToken.IsCancellationRequested && (bytesRead = await result.Result.ReadAsync(data, 0, data.Length, cancellationToken)) > 0)
{
await s.WriteAsync(data, 0, bytesRead, cancellationToken);
await s.FlushAsync(cancellationToken);
}
response.Dispose();
};
// Return Response container
return proxyResponse;
}
}
}
}
When I run it, I get through the while loop a couple times but then get an exception in FrameResponseStream (Krestrel): "System.ObjectDisposedException: 'Cannot access a disposed object.'" It appears that the stream is being closed (_state = FrameStreamState.Closed -- https://github.com/aspnet/KestrelHttpServer/blob/rel/2.0.0/src/Microsoft.AspNetCore.Server.Kestrel.Core/Internal/Http/FrameResponseStream.cs) prematurely but I cannot figure out why or what I need to change to resolve it!
You should use ResponseContentRead instead of ResponseHeadersRead
HttpResponseMessage response = await httpClient.GetAsync(Request.Query["url"],
HttpCompletionOption.ResponseContentRead, cancellationToken);
I have an entity CallTrackerLog which has many Clients which have a one-many Advices. I am trying to HttpPost a create for the advice:
[HttpPost("{callTrackerId}/{clientId}/advice")]
public IActionResult CreateCTClientAdvice(int callTrackerId, int clientId,
[FromBody] CallTrackerClientAdvice newAdvice)
{
if (newAdvice == null)
return BadRequest();
if (!ModelState.IsValid)
return BadRequest(ModelState);
var ctFromStore = _context.CallTrackers
.Include(log => log.CallTrackerClients)
.ThenInclude(log => log.CallTrackerClientAdvice)
.FirstOrDefault(ct => ct.CallTrackerId == callTrackerId);
var ctAdviceFromStore ctFromStore.CallTrackerClients.CallTrackerClientAdvice
.FirstOrDefault(c => c.CallTrackerClientId == clientId);
// ... add to db
return Ok();
}
The problem is that I cannot access the CallTrackerClientAdvice with the .FirstOrDefault(ct => ct.CallTrackerClientId == clientId) - it gives me a red underline even though I thought I loaded it above.
The error:
How come I am unable to access the CallTrackerClientAdvice?
I suspect that what you want is:
var ctAdviceFromStore = ctFromStore.CallTrackerClients
.FirstOrDefault(c => c.CallTrackerClientId == clientId)?.CallTrackerClientAdvice;
I have a Web API 2 POST endpoint which takes a parameter, queries the database and returns an xml string as the response.
public async Task<IHttpActionResult> Post(long groupId)
{
People people = await _someService.GetPeople(groupId);
XElement peopleXml = _xmlService.ConverToXml(people);
return Ok(peopleXml);
}
How do I to return the xml as a file instead?
Figured it out myself, but I hope there is a simpler way -
public async Task<IHttpActionResult> Post(long groupId)
{
People people = await _someService.GetPeople(groupId);
XElement peopleXml = _xmlService.ConverToXml(people);
byte[] toBytes = Encoding.Unicode.GetBytes(peopleXml.ToString());
var stream = new MemoryStream(toBytes);
var result = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StreamContent(stream)
};
result.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment")
{
FileName = "test.txt"
};
result.Content.Headers.ContentType = new MediaTypeHeaderValue("text/plain");
var response = ResponseMessage(result);
return response;
}
In a Silverlight 5 application in Dynamics CRM 2011 I access the Organization Service of the CRM to query for entity Metadata. I wrote a service that takes an entity name and returns a list of all its fields.
How can I test this service method automatically? The main problem is how to obtain a reference to the organization service from a Silverlight app that does not run in the context of the CRM.
My Service method looks like this:
public IOrganizationService OrganizationService
{
get
{
if (_organizationService == null)
_organizationService = SilverlightUtility.GetSoapService();
return _organizationService;
}
set { _organizationService = value; }
}
public async Task<List<string>> GetAttributeNamesOfEntity(string entityName)
{
// build request
OrganizationRequest request = new OrganizationRequest
{
RequestName = "RetrieveEntity",
Parameters = new ParameterCollection
{
new XrmSoap.KeyValuePair<string, object>()
{
Key = "EntityFilters",
Value = EntityFilters.Attributes
},
new XrmSoap.KeyValuePair<string, object>()
{
Key = "RetrieveAsIfPublished",
Value = true
},
new XrmSoap.KeyValuePair<string, object>()
{
Key = "LogicalName",
Value = "avobase_tradeorder"
},
new XrmSoap.KeyValuePair<string, object>()
{
Key = "MetadataId",
Value = new Guid("00000000-0000-0000-0000-000000000000")
}
}
};
// fire request
IAsyncResult result = OrganizationService.BeginExecute(request, null, OrganizationService);
// wait for response
TaskFactory<OrganizationResponse> tf = new TaskFactory<OrganizationResponse>();
OrganizationResponse response = await tf.FromAsync(
OrganizationService.BeginExecute(request, null, null), iar => OrganizationService.EndExecute(result));
// parse response
EntityMetadata entities = (EntityMetadata)response["EntityMetadata"];
return entities.Attributes.Select(attr => attr.LogicalName).ToList();
}
Edit:
I can create and execute unit tests with Resharper and AgUnit. Thus, the problem is not how to write a unit test in general.
I have tweaked the GetSoapService from the standard Microsoft SDK to accept a fall back value. This means no codes changes are needed when debugging in visual studio and running in CRM. Anyway here it is
public static IOrganizationService GetSoapService(string FallbackValue = null)
{
Uri serviceUrl = new Uri(GetServerBaseUrl(FallbackValue)+ "/XRMServices/2011/Organization.svc/web");
BasicHttpBinding binding = new BasicHttpBinding(Uri.UriSchemeHttps == serviceUrl.Scheme
? BasicHttpSecurityMode.Transport : BasicHttpSecurityMode.TransportCredentialOnly);
binding.MaxReceivedMessageSize = int.MaxValue;
binding.MaxBufferSize = int.MaxValue;
binding.SendTimeout = TimeSpan.FromMinutes(20);
IOrganizationService ser =new OrganizationServiceClient(binding, new EndpointAddress(serviceUrl));
return ser;
}
public static string GetServerBaseUrl(string FallbackValue = null)
{
try
{
string serverUrl = (string)GetContext().Invoke("getClientUrl");
//Remove the trailing forwards slash returned by CRM Online
//So that it is always consistent with CRM On Premises
if (serverUrl.EndsWith("/"))
{
serverUrl = serverUrl.Substring(0, serverUrl.Length - 1);
}
return serverUrl;
}
catch
{
//Try the old getServerUrl
try
{
string serverUrl = (string)GetContext().Invoke("getServerUrl");
//Remove the trailing forwards slash returned by CRM Online
//So that it is always consistent with CRM On Premises
if (serverUrl.EndsWith("/"))
{
serverUrl = serverUrl.Substring(0, serverUrl.Length - 1);
}
return serverUrl;
}
catch
{
return FallbackValue;
}
}
I am creating a silverlight application as a web resource for CRM 2011. Now i am creating a ServiceAppointment record in DB and after creating it i want to change its Status to "reserved" instead of requested.
I googled about this and come across the examples like Close a Service Activity Through Code and Microsoft.Crm.Sdk.Messages.SetStateRequest
They all suggesting to use "SetStateRequest" and for using this i have to set the OptionSetValue like
request["State"] = new OptionSetValue(4);
But above line gives me error saying "OptionSetValue does not contain constructor which takes one argument"
BTW i am using SOAP end point of CRM 2011 service in silverlight application
Any ideas friends?
EDIT
Following is my code
var request = new OrganizationRequest { RequestName = "SetStateRequest" };
request["State"] = 3;
request["Status"] = 4;
request["EntityMoniker"] = new EntityReference() { Id = createdActivityId, LogicalName = "serviceappointment" };
crmService.BeginExecute(request,ChangeActivityStatusCallback,crmService);
And my callback function is
private void ChangeActivityStatusCallback(IAsyncResult result) {
OrganizationResponse response;
try
{
response = ((IOrganizationService)result.AsyncState).EndExecute(result);
}
catch (Exception ex)
{
_syncContext.Send(ShowError, ex);
return;
}
}
You must some how be referencing some other OptionSetValue class that is not the Microsoft.Xrm.Sdk one. Try appending the namespace to see if that resolves your issue:
request["State"] = new Microsoft.Xrm.Sdk.OptionSetValue(4);
Also, why are you using late bound on the SetStateRequest? Just use the SetStateRequest class:
public static Microsoft.Crm.Sdk.Messages.SetStateResponse SetState(this IOrganizationService service,
Entity entity, int state, int? status)
{
var setStateReq = new Microsoft.Crm.Sdk.Messages.SetStateRequest();
setStateReq.EntityMoniker = entity.ToEntityReference();
setStateReq.State = new OptionSetValue(state);
setStateReq.Status = new OptionSetValue(status ?? -1);
return (Microsoft.Crm.Sdk.Messages.SetStateResponse)service.Execute(setStateReq);
}
Thanks Daryl for you time and effort. I have solved my problem with the way u have suggested.
I am posting my code that worked for me.
var request = new OrganizationRequest { RequestName = "SetState" };
request["State"] = new OptionSetValue { Value = 3 };
request["Status"] = new OptionSetValue { Value = 4 };
request["EntityMoniker"] = new EntityReference() { Id = createdActivityId, LogicalName = "serviceappointment" };
crmService.BeginExecute(request,ChangeActivityStatusCallback,crmService);
private void ChangeActivityStatusCallback(IAsyncResult result) {
OrganizationResponse response;
try
{
response = ((IOrganizationService)result.AsyncState).EndExecute(result);
}
catch (Exception ex)
{
_syncContext.Send(ShowError, ex);
return;
}
}