I'm hosting a service and trying to pass it a url as a parameter ... I know I've got to encode the url - but when I put a break point inside my method it only gets hit if I pass certain encodings - not others such a forward slash ...
So ...
http://myurl.com:8181/blah
works fine - even something like (encoded colon) ...
http://myurl.com:8181/blah%3A
but if I try to pass an encoded slash
http://myurl.com:8181/blah%2F
I get 'Endpoint not found' and my breakpoint isn't hit ...
Can anyone assist please?
Code below ...
Hosting the service ...
var instantPrintService = new WebServiceHost(typeof(InstantPrintService), new Uri("http://myurl:8181/"));
instantPrintService.Open();
The interface ....
[ServiceContract]
public interface IInstantPrint
{
[OperationContract]
[WebGet(UriTemplate = "printlabel/{filepath}", ResponseFormat = WebMessageFormat.Json )]
Response PrintLabel(string filepath);
}
The print label method ...
public Response PrintLabel(string filepath)
{
try
{
return new Response { Success = true, Message = "Success" };
}
catch (Exception ex)
{
return new Response { Success = false, Message = ex.ToString() };
}
}
Related
I am a total noob in C# and tried to add an automated mail services to my backend API for an Angular FrontEnd.
It works properly as intended for one time, but cannot be used a second time. I guess I am violating some object rules, maybe someone is able to point out my mistake.
This is an excerpt of my file UserAuthController.cs which includes the register function. When registration on my website is successful it shall also call the API Service from my automated mail system.
I didn't know how to include the function properly so I've added it with a new namespace.
namespace Gogo_Api.Controllers
{
[RoutePrefix("UserAuth")]
[EnableCors(origins: "*", headers: "*", methods: "*")]
public class UserAuthController : ApiController
{
private readonly IUserAuthManager _userAuthManager;
public UserAuthController()
{
}
public UserAuthController(IUserAuthManager userAuthManager)
{
this._userAuthManager = userAuthManager;
}
[HttpPost]
[Route("Register")]
public HttpResponseMessage Register(UserDetails user)
{
var response = new RegisterResponse();
response.code = _userAuthManager.Register(user);
if (response.code == 1)
{
response.message = "Registration successful ";
//Including API Service here...
Sendinblue.Program RegisterMail = new Sendinblue.Program();
RegisterMail.Main(user.email, user.displayName, user.country);
RegisterMail = null;
}
else if (response.code == 2)
{
response.message = "User already registered ";
}
else if (response.code == 0)
{
response.message = "Error occured";
}
return Request.CreateResponse(HttpStatusCode.OK, response);
}
}
}
namespace Sendinblue
{
class Program
{
public void Main(string userMail, string userName, string userCountry)
{
Configuration.Default.ApiKey.Add("api-key", "MYKEY");
var apiInstance = new ContactsApi();
string email = userMail;
JObject attributes = new JObject();
attributes.Add("USERNAME", userName);
attributes.Add("COUNTRY", userCountry);
List<long?> listIds = new List<long?>();
listIds.Add(5);
try
{
var createContact = new CreateContact(email, attributes, emailBlacklisted, smsBlacklisted, listIds, updateEnabled, smtpBlacklistSender);
CreateUpdateContactModel result = apiInstance.CreateContact(createContact);
}
catch (Exception e)
{
Debug.WriteLine(e.Message);
Console.WriteLine(e.Message);
}
}
}
}
I have added 'RegisterMail = null;' because I thought I need to delete my object first before using it again, but still it works only for the first time.
How would I be able to call my function multiple times?
Thanks
Thanks #Richard Barker, your comment helped me fix it.
I have moved everything out of the Controller and had to move
Configuration.Default.ApiKey.Add...
apiInstance = new ContactsApi();
to a one-time call in the Initializer, so the API Call and ContactsApi is only created once, instead of everytime.
I am trying to invoke External APIs from AWS lambda function written in c#. The Lamda function is deployed in No VPC mode. I am calling this function from Alexa skill. The code works fine for an http request, but its not working for https.
The below code works when I use http://www.google.com.
But, if I replace http with https, then I get the error in the cloud watch saying:
"Process exited before completing request."
Even the log written in catch is not getting logged in cloud watch.
public class Function
{
public const string INVOCATION_NAME = "bingo";
public async Task<SkillResponse> FunctionHandler(SkillRequest input, ILambdaContext context)
{
var requestType = input.GetRequestType();
if (requestType == typeof(IntentRequest))
{
string response = "";
IntentRequest request = input.Request as IntentRequest;
response += $"About {request.Intent.Slots["carmodel"].Value}";
try
{
using (var httpClient = new HttpClient())
{
Console.WriteLine("Trying to access internet");
//var resp=httpClient.GetAsync("http://www.google.com").Result // this works perfect!
var resp = httpClient.GetAsync("https://www.google.com").Result; // this throws error
Console.WriteLine("Call was successful");
}
}
catch (Exception ex)
{
Console.WriteLine("Exception from main function " + ex.Message);
Console.WriteLine(ex.InnerException.Message);
Console.WriteLine(ex.StackTrace);
}
return MakeSkillResponse(response, true);
}
else
{
return MakeSkillResponse(
$"I don't know how to handle this intent. Please say something like Alexa, ask {INVOCATION_NAME} about Tesla.",
true);
}
}
private SkillResponse MakeSkillResponse(string outputSpeech, bool shouldEndSession,
string repromptText = "Just say, tell me about car models to learn more. To exit, say, exit.")
{
var response = new ResponseBody
{
ShouldEndSession = shouldEndSession,
OutputSpeech = new PlainTextOutputSpeech { Text = outputSpeech }
};
if (repromptText != null)
{
response.Reprompt = new Reprompt() { OutputSpeech = new PlainTextOutputSpeech() { Text = repromptText } };
}
var skillResponse = new SkillResponse
{
Response = response,
Version = "1.0"
};
return skillResponse;
}
}
The issue was resolved by updating the library version.
System.Net.Http v4.3.4 was not completely compatible with dotnet core v1.
So outbound http calls were working but not https calls. Changing the version of System.net.http resolved the issue.
I have a MVC 5 backend written in C#. It serves MVC views written in Razor and also some Angular 2 pages.
What is the best way to handle potential errors when calling server from client? I really would like to establish a pattern that is robust and works in all situations. Below is what I have tried so far.
Backend C# code:
public class MyController : Controller
{
[HttpGet]
public ActionResult GetUsers()
{
try
{
// Lot of fancy server code ...
throw new Exception("Dummy error");
return GetCompressedResult(json);
}
catch (Exception ex)
{
throw new HttpException(501, ex.Message);
}
}
private FileContentResult GetCompressedResult(string json)
{
// Transform to byte array
var bytes = Encoding.UTF8.GetBytes(json);
// Compress array
var compressedBytes = bytes.Compress();
HttpContext.Response.AppendHeader("Content-encoding", "gzip");
return new FileContentResult(compressedBytes, "application/json");
}
}
Client side Angular 2 code:
public loadDataFromServer() {
let response = this.http.get(this.urlGetData)
.map((res: Response) => res.json())
.catch(this.handleError);
response.subscribe(response => {
// Process valid result ...
},
err => { console.error(err); }
);
};
private handleError(error: Response | any) {
let errMsg: string;
if (error instanceof Response) {
const body = JSON.parse(JSON.stringify(error || null))
const err = body.error || JSON.stringify(body);
errMsg = `${error.status} - ${error.statusText || ''} ${err}`;
} else {
errMsg = error.message ? error.message : error.toString();
}
console.error(errMsg);
return Observable.throw(errMsg);
}
This is a printscreen of the error object processed by handleError method:
This all raises some questions:
Is it correct to throw custom HttpException from server?
Is handleError method correct or maybe too complex?
On client side I would like to see the custom error message, but currently it is just found in an enormous "blob" of HTML that is nasty to parse.
Is client side error handling necessary BOTH in get call and subscribe action?
My current suggestion is to let server respond with Json object for all handled exceptions.
On client side I check result object for possible error property before handling valid result.
The handleResponseError method will parse typed Response object and throw observable message. But at least my browser (Chrome 57) seems to automatically log response errors to console. So if subscriber need no specific extra handling for different errors, then the subscriber need no extra action for err object.
Please feedback if there are better ways!
Backend C# code:
public class MyController : Controller
{
[HttpGet]
public ActionResult GetUsers()
{
try
{
// Lot of fancy server code ...
throw new ArgumentException("Dummy error");
// Normal return of result ...
}
catch (Exception ex)
{
return Json(new { error = $"{ex.GetType().FullName}: '{ex.Message}'" }, JsonRequestBehavior.AllowGet);
}
}
}
Client side Angular 2 code:
public loadDataFromServer() {
let response = this.http.get(this.urlGetData)
.map((res: Response) => res.json())
.catch(this.handleResponseError);
response.subscribe(result => {
if (result.error) {
this.displayJsonError(this.urlGetUsers, result.error);
}
else {
// Process valid result
}
});
};
private handleResponseError(value: Response | any) {
let errorMessage = value.toString();
let response = value as Response;
if (response) {
errorMessage = `${response.status}: ${response.statusText}\n${response.toString()}`;
}
if (value.error) {
errorMessage = value.error;
}
if (value.message) {
errorMessage = value.message;
}
return Observable.throw(errorMessage);
}
private displayJsonError(url: string, error: string) {
console.error(`Call to '${url}' failed with ${error}`);
}
Simple Scenario:
Client makes a AJAX Sync call to a central WCF server ==> url: "svc/About.svc/GetAboutInfo";
The WCF "GetAboutInfo()" will call "GetSiteInfo()" in 80 remote servers;
I get the results but it takes awhile since these are NOT Async calls;
With that in mind I have 2 things to fix (but I don't know how):
1 - make GetSiteInfo() a Async call;
2 - only return GetAboutInfo() to the client after ALL Async calls from GetSiteInfo() are returned;
Note: I cannot use "Tasks" since we are still on .Net 3.5.
Currently I am researching about IAsyncResult (with Begin/End methods) but could not find anything that would allow me to adapt to my current code below.
(I am calling remote servers from a central WCF in a loop).
Bear in mind the WCF below is identical in all remote servers except that the loop which only exists in the "CENTRAL WCF server"(the WCF that calls the remote servers). Here is the partial WCF code:
[ServiceContract]
public interface IAbout
{
[OperationContract(Name = "About_GetAboutInfo")]
[WebGet(UriTemplate = "/GetAboutInfo", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
About.AboutInfo GetAboutInfo();
[OperationContract(Name = "About_GetSiteInfo")]
[WebGet(UriTemplate = "/GetSiteInfo", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
About.SiteInfo GetSiteInfo();
}
public SiteInfo GetSiteInfo()
{
SiteInfo siteInfo = new SiteInfo();
//...code stripped out...
return (siteInfo);
}
public AboutInfo GetAboutInfo()
{
AboutInfo aboutInfo = new AboutInfo();
SiteInfo siteInfo = new SiteInfo()
{
ID = site.ID
,Name = site.Name
,DatabaseVersion = "Unavailable"
};
foreach (Site site in sites)
{
try
{
string uri = Utilities.CombineUri(site.Uri, "svc/About.svc/ws");
AboutServiceClient wcfClient = new AboutServiceClient("About");
wcfClient.Endpoint.Address = new EndpointAddress(uri);
SiteInfo childSiteInfo = wcfClient.GetSiteInfo(); <== call is blocked here until I get a response from remote server
siteInfo.DatabaseVersion = childSiteInfo.DatabaseVersion;
}
catch (Exception e)
{ //...code stripped out... }
aboutInfo.Sites.Add(siteInfo); <== this should only be returned after we receive response from all calls
}
...
public class AboutServiceClient : ClientBase<IAbout>
{
public AboutServiceClient(Binding Binding, EndpointAddress Address) : base(Binding, Address)
{
if (Binding is WebHttpBinding)
{
this.Endpoint.Behaviors.Add(new WebHttpBehavior());
}
}
public AboutServiceClient(string endpointConfigurationName) : base(endpointConfigurationName)
{ }
public About.SiteInfo GetSiteInfo()
{ return base.Channel.GetSiteInfo(); }
public About.AboutInfo GetAboutInfo()
{ return base.Channel.GetAboutInfo(); }
}
Thank you
Using .NET 3.5 is a major restrain. You won't be able to keep your linear code flow. Here's the new workflow:
You'd need to implement BeginGetAboutInfo/EndGetAboutInfo as described in "How to: Implement an Asynchronous Service Operation".
In BeginGetAboutInfo you'd do start 80 asynchronous requests to the remote WCF service with wcfClient.GetSiteInfoBegin (in parallel) and keep track of IAsyncResult of each.
As these asynchronous operation are completing (your callback will be called for each), use wcfClient.EndSiteInfoBegin to retriever and store the result of each operation.
As soon as all of them have completed, invoke the callback, provided by the client when your BeginGetAboutInfo was called.
Now expect the client to call your EndGetAboutInfo, where you'd provide the combined result of all 80 operations.
You can install the "Task Parallel Library for .NET 3.5" from NuGEt and use tasks that way. Then you can wrap you wcfClient.GetSiteInfoBegin and wcfClient.EndSiteInfoBegin methods with Task.Factory.FromAsync.
This is untested, but maybe something like this:
public AboutInfo GetAboutInfo()
{
AboutInfo aboutInfo = new AboutInfo();
SiteInfo siteInfo = new SiteInfo()
{
ID = site.ID
,Name = site.Name
,DatabaseVersion = "Unavailable"
};
var tasks = new List<Task<SiteInfo>>();
foreach (Site site in sites)
{
try
{
string uri = Utilities.CombineUri(site.Uri, "svc/About.svc/ws");
AboutServiceClient wcfClient = new AboutServiceClient("About");
wcfClient.Endpoint.Address = new EndpointAddress(uri);
tasks.Add(Task<SiteInfo>.Factory.FromAsync(wcfClient.GetSiteInfoBegin, wcfClient.EndSiteInfoBegin, null)
.ContinueWith(t =>
{
siteInfo.DatabaseVersion = t.Result.DatabaseVersion.DatabaseVersion;
}, TaskScheduler.FromCurrentSynchronizationContext()));
}
catch (Exception e)
{ //...code stripped out...
}
}
Task.WhenAll(tasks.ToArray()).ContinueWith
( ts =>
{
ts.ForEach( t => aboutInfo.Sites.Add(t.Rrsult);
});
return aboutInfo;
}
I've seen several references to WebServiceHost2Factory as the class to use to effectively handle errors in WCF Rest services. Apparently with that class, I just had to throw a WebProtocolException and the body of the response would contain pertinent information.
That class seems to have fallen out of favor now. Is there a replacement somewhere in the .NET 4 stack?
I'm trying to figure out how to return error text in the body of a response to a POST operation, if something went wrong. The key question is below next to all the *'s
Example:
[Description("Performs a full enroll and activation of the member into the Loyalty program")]
[OperationContract]
[WebInvoke(Method = "POST", UriTemplate = "/fullenroll/{clientDeviceId}",
BodyStyle = WebMessageBodyStyle.Bare,
RequestFormat = WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json)]
public MemberInfo FullEnroll(string clientDeviceId, FullEnrollmentRequest request)
{
Log.DebugFormat("FullEnroll. ClientDeviceId: {0}, Request:{1}", clientDeviceId, request);
MemberInfo ret = null;
try
{
//Do stuff
}
catch (FaultException<LoyaltyException> fex)
{
Log.ErrorFormat("[loyalty full enroll] Caught faultexception attempting to full enroll. Message: {0}, Reason: {1}, Data: {2}", fex.Message, fex.Reason, fex.Detail.ExceptionMessage);
HandleException("FullEnroll", fex, fex.Detail.ExceptionMessage);
}
catch (Exception e)
{
Log.ErrorFormat(
"[loyalty full enroll] Caught exception attempting to full enroll. Exception: {0}", e);
HandleException("FullEnroll", e);
}
return ret;
}
/// <summary>
/// Deals w/ the response when Exceptions are thrown
/// </summary>
private static Exception HandleException(string function, Exception e, string statusMessage = null)
{
// Set the return context, handle the error
if (WebOperationContext.Current != null)
{
var response = WebOperationContext.Current.OutgoingResponse;
// Set the error code based on the Exception
var errorNum = 500;
if (e is HttpException)
errorNum = ((HttpException)e).ErrorCode;
response.StatusCode = (HttpStatusCode) Enum.Parse(typeof (HttpStatusCode), errorNum.ToString());
response.StatusDescription = statusMessage;
// ****************************************************
// How can I return this as the body of the Web Method?
// ****************************************************
WebOperationContext.Current.CreateTextResponse(statusMessage);
}
return (e is HttpException) ? e : new HttpException(500, string.Format("{0} caught an exception", function));
}
This answer seems to suggest using the following,
HttpContext.Current.Response.Write(statusMessage);
Edit - As tobyb mentioned in the comments, AspNetCompatibility is required.
Here's how to turn it on:
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true">
<!-- ... -->
</system.serviceModel>