Reading SyndicationFeed in background - push-notification

Uri uri = new Uri( feedUri);
SyndicationClient client = new SyndicationClient();
SyndicationFeed currentFeed = await client.RetrieveFeedAsync(uri);
XmlDocument toastXml = ToastNotificationManager.GetTemplateContent(ToastTemplateType.ToastImageAndText03);
XmlNodeList toastTextElement = toastXml.GetElementsByTagName("text");
toastTextElement[0].AppendChild(toastXml.CreateTextNode("Working"));
ToastNotification toast = new ToastNotification(toastXml);
ToastNotificationManager.CreateToastNotifier().Show(toast);
nothing is being executed after RetrieveFeedAsync.

try to add deferal to your Running Background
public async void Run(IBackgroundTaskInstance taskInstance)
{
BackgroundTaskDeferral deferral = taskInstance.GetDeferral();
//YOUR CODE GOES HERE
deferral.Complete();
}

Related

Read Asp.Net Core Response body in ActionFilterAttribute

I'm using Asp.Net Core as a Rest Api Service.
I need access to request and response in ActionFilter. Actually, I found the request in OnActionExcecuted but I can't read the response result.
I'm trying to return value as follow:
[HttpGet]
[ProducesResponseType(typeof(ResponseType), (int)HttpStatusCode.OK)]
[Route("[action]")]
public async Task<IActionResult> Get(CancellationToken cancellationToken)
{
var model = await _responseServices.Get(cancellationToken);
return Ok(model);
}
And in ActionFilter OnExcecuted method as follow:
_request = context.HttpContext.Request.ReadAsString().Result;
_response = context.HttpContext.Response.ReadAsString().Result; //?
I'm trying to get the response in ReadAsString as an Extension method as follow:
public static async Task<string> ReadAsString(this HttpResponse response)
{
var initialBody = response.Body;
var buffer = new byte[Convert.ToInt32(response.ContentLength)];
await response.Body.ReadAsync(buffer, 0, buffer.Length);
var body = Encoding.UTF8.GetString(buffer);
response.Body = initialBody;
return body;
}
But, there is no result!
How I can get the response in OnActionExcecuted?
Thanks, everyone for taking the time to try and help explain
If you're logging for json result/ view result , you don't need to read the whole response stream. Simply serialize the context.Result:
public class MyFilterAttribute : ActionFilterAttribute
{
private ILogger<MyFilterAttribute> logger;
public MyFilterAttribute(ILogger<MyFilterAttribute> logger){
this.logger = logger;
}
public override void OnActionExecuted(ActionExecutedContext context)
{
var result = context.Result;
if (result is JsonResult json)
{
var x = json.Value;
var status = json.StatusCode;
this.logger.LogInformation(JsonConvert.SerializeObject(x));
}
if(result is ViewResult view){
// I think it's better to log ViewData instead of the finally rendered template string
var status = view.StatusCode;
var x = view.ViewData;
var name = view.ViewName;
this.logger.LogInformation(JsonConvert.SerializeObject(x));
}
else{
this.logger.LogInformation("...");
}
}
I know there is already an answer but I want to also add that the problem is the MVC pipeline has not populated the Response.Body when running an ActionFilter so you cannot access it. The Response.Body is populated by the MVC middleware.
If you want to read Response.Body then you need to create your own custom middleware to intercept the call when the Response object has been populated. There are numerous websites that can show you how to do this. One example is here.
As discussed in the other answer, if you want to do it in an ActionFilter you can use the context.Result to access the information.
For logging whole request and response in the ASP.NET Core filter pipeline you can use Result filter attribute
public class LogRequestResponseAttribute : TypeFilterAttribute
{
public LogRequestResponseAttribute() : base(typeof(LogRequestResponseImplementation)) { }
private class LogRequestResponseImplementation : IAsyncResultFilter
{
public async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
{
var requestHeadersText = CommonLoggingTools.SerializeHeaders(context.HttpContext.Request.Headers);
Log.Information("requestHeaders: " + requestHeadersText);
var requestBodyText = await CommonLoggingTools.FormatRequestBody(context.HttpContext.Request);
Log.Information("requestBody: " + requestBodyText);
await next();
var responseHeadersText = CommonLoggingTools.SerializeHeaders(context.HttpContext.Response.Headers);
Log.Information("responseHeaders: " + responseHeadersText);
var responseBodyText = await CommonLoggingTools.FormatResponseBody(context.HttpContext.Response);
Log.Information("responseBody: " + responseBodyText);
}
}
}
In Startup.cs add
app.UseMiddleware<ResponseRewindMiddleware>();
services.AddScoped<LogRequestResponseAttribute>();
Somewhere add static class
public static class CommonLoggingTools
{
public static async Task<string> FormatRequestBody(HttpRequest request)
{
//This line allows us to set the reader for the request back at the beginning of its stream.
request.EnableRewind();
//We now need to read the request stream. First, we create a new byte[] with the same length as the request stream...
var buffer = new byte[Convert.ToInt32(request.ContentLength)];
//...Then we copy the entire request stream into the new buffer.
await request.Body.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false);
//We convert the byte[] into a string using UTF8 encoding...
var bodyAsText = Encoding.UTF8.GetString(buffer);
//..and finally, assign the read body back to the request body, which is allowed because of EnableRewind()
request.Body.Position = 0;
return $"{request.Scheme} {request.Host}{request.Path} {request.QueryString} {bodyAsText}";
}
public static async Task<string> FormatResponseBody(HttpResponse response)
{
//We need to read the response stream from the beginning...
response.Body.Seek(0, SeekOrigin.Begin);
//...and copy it into a string
string text = await new StreamReader(response.Body).ReadToEndAsync();
//We need to reset the reader for the response so that the client can read it.
response.Body.Seek(0, SeekOrigin.Begin);
response.Body.Position = 0;
//Return the string for the response, including the status code (e.g. 200, 404, 401, etc.)
return $"{response.StatusCode}: {text}";
}
public static string SerializeHeaders(IHeaderDictionary headers)
{
var dict = new Dictionary<string, string>();
foreach (var item in headers.ToList())
{
//if (item.Value != null)
//{
var header = string.Empty;
foreach (var value in item.Value)
{
header += value + " ";
}
// Trim the trailing space and add item to the dictionary
header = header.TrimEnd(" ".ToCharArray());
dict.Add(item.Key, header);
//}
}
return JsonConvert.SerializeObject(dict, Formatting.Indented);
}
}
public class ResponseRewindMiddleware {
private readonly RequestDelegate next;
public ResponseRewindMiddleware(RequestDelegate next) {
this.next = next;
}
public async Task Invoke(HttpContext context) {
Stream originalBody = context.Response.Body;
try {
using (var memStream = new MemoryStream()) {
context.Response.Body = memStream;
await next(context);
//memStream.Position = 0;
//string responseBody = new StreamReader(memStream).ReadToEnd();
memStream.Position = 0;
await memStream.CopyToAsync(originalBody);
}
} finally {
context.Response.Body = originalBody;
}
}
You can also do...
string response = "Hello";
if (result is ObjectResult objectResult)
{
var status = objectResult.StatusCode;
var value = objectResult.Value;
var stringResult = objectResult.ToString();
responce = (JsonConvert.SerializeObject(value));
}
I used this in a .net core app.
Hope it helps.

converting a asp.net mvc to a razor page

I have a asp.net web app that calls a controller action with the following code:
$(function () {
$("#barcode").on("change", function (e) {
// get the current value
var barcode = $('#barcode').val();
// if there's no text, ignore the event
if (!barcode) {
return;
}
// clear the textbox
$("#barcode").val("");
// var holdit = $('#textArea1').val();
$('#textArea1').val($('#textArea1').val() +' '+ barcode);
// post the data using AJAX
$.post('#Url.Action("scanned", "receiveScan")?barcode=' + barcode);
});
})
Controller:
[Produces("application/json")]
[Route("api/receiveScan")]
public class receiveScanController : Controller
{
private static readonly HttpClient client = new HttpClient();
public ActionResult scanned(string barcode)
{
var test = barcode;
receiveScanModel newScan = new receiveScanModel();
newScan.Barcode = barcode;
newScan.companyNo = 1;
string jsonScan = JsonConvert.SerializeObject(newScan, Formatting.Indented);
var httpWebRequest = (HttpWebRequest)WebRequest.Create("http://notarealservicehere.azurewebsites.net//api/receivescan");
httpWebRequest.ContentType = "application/json";
httpWebRequest.Method = "POST";
using (var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream()))
{
streamWriter.Write(jsonScan);
}
var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
return Ok();
Trying to convert to my first Razor page, everything works with the exception (obviously) of the $.post part...
Where would this go?
It is a asp.net core app with razor pages
Use a handler for example
on your cs file
public IActionResult OnPostBarcode(string barcode)
on your js
var uri = "myPage/?handler=Barcode"
$.post( uri ,{barcode:barcode}, function( data ) {
console.log(data)
});

How to change "to-reply" property of email in alfresco

I am able to send emails in alfresco using Java API but I am not able to change the "Reply-to: " property like this in alfresco :
Message replyMessage = new MimeMessage(session);
replyMessage = (MimeMessage) message.reply(false);
replyMessage.setFrom(new InternetAddress(to));
replyMessage.setText("Thanks");
replyMessage.setReplyTo(message.getReplyTo());
replyMessage.setReplyTo(message.getReplyTo());
This is my code to send emails
NodeRef companyHome = repository.getCompanyHome();
List<String> pathElements = new ArrayList<>();
pathElements.add("Data Dictionary");
pathElements.add("Email Templates");
pathElements.add("Trams Email Templates");
pathElements.add("CONTENT_NOTIFICATION.html.ftl");
FileInfo templateFile;
try {
templateFile = serviceRegistry.getFileFolderService()
.resolveNamePath(companyHome, pathElements);
NodeRef template = templateFile.getNodeRef();
List<String> users = new ArrayList<String>();
users.add(userName);
ActionService actionService = serviceRegistry.getActionService();
Action mailAction = actionService.createAction(MailActionExecuter.NAME);
mailAction.setParameterValue(MailActionExecuter.PARAM_TEMPLATE, template);
Map<String, Serializable> templateArgs = new HashMap<String, Serializable>();
templateArgs.put("userName", userName);
Map<String, Serializable> templateModel = new HashMap<String, Serializable>();
templateModel.put("args",(Serializable)templateArgs);
mailAction.setParameterValue(MailActionExecuter.PARAM_TEMPLATE_MODEL,(Serializable)templateModel);
mailAction.setParameterValue(MailActionExecuter.PARAM_SUBJECT, "Content Notification");
mailAction.setParameterValue(MailActionExecuter.PARAM_TO_MANY, (Serializable) users);
actionService.executeAction(mailAction, null);
} catch (org.alfresco.service.cmr.model.FileNotFoundException e) {
e.printStackTrace();
}
Is there any way to enable this replyTo parameter in alfresco ?
Please help.
I have override the OOTB MailActionExecuter class.
added my code to set the replyTo parameter
I fixed parameter from java class mailAction.setParameterValue(MailActionExecuter.PARAM_REPLY_TO,"myEmail#gmail.com");
and access using
public static final String PARAM_REPLY_TO = "reply_to";
message.setReplyTo(replyTo);

Accessing the returned XML from an API call

I have the following action method to perform an API call:-
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(Rack rack, FormCollection formValues)
{
if (ModelState.IsValid) {
using (var client = new WebClient())
{
var query = HttpUtility.ParseQueryString(string.Empty);
foreach (string key in formValues)
{
query[key] = this.Request.Form[key];
}
query["username"] = "testuser";
query["password"] = ///.....
query["assetType"] = "Rack";
query["operation"] = "AddAsset";
var url = new UriBuilder("http://win-spdev:8400/servlets/AssetServlet");
url.Query = query.ToString();
try
{
string xml = client.DownloadString(url.ToString());
}
The return XML from the API call looks as follow:-
<operation>
<operationstatus>Failure</operationstatus>
<message>Rack already exists.Unable to add</message>
</operation>
but how i can reach the message and operationstaus and according to them to display an appropriate message . i use to serialize the returned Json such as , but i am not sure how to do so for the xML:-
var serializer = new JavaScriptSerializer();
var myObject = serializer.Deserialize<newprocess>(json);
string activityid = myObject.activityId;
Just load it into an XmlDocument.
Untested and from the top of my head:
var xmlDoc = new XmlDocument();
xmlDoc.LoadXml(theXML);
var status = xmlDoc.SelectSingleNode("/operation/operationstatus").InnerText;
var message = xmlDoc.SelectSingleNode("/operation/message").InnerText;
If you using ASP.NET mvc, I believe you can use HttpClient, instead of WebClient:
Define result class:
public class operation
{
public string operationstatus{get;set;}
public string message{get;set;}
}
And then use it for automatic deserilization:
var client = new HttpClient();
var result = client.PostAsync(url,
new FormUrlEncodedContent(new Dictionary<string, string>{
{"username","testuser"},
{"assetType","Rack"}}))
.Result.Content
.ReadAsAsync<operation>().Result;

Reading a RSS feed using visual C#

I am trying to a read a RSS feed and display in my C# application. i have used the code below and it works perfectly for other RSS feeds. I want to read this RSS feed ---> http://ptwc.weather.gov/ptwc/feeds/ptwc_rss_indian.xml and the code below doesn't work for it. I don't get any errors but nothing happens, the text box which i want the RSS feed to be displayed is empty. Please help. What am I doing wrong?
public class RssNews
{
public string Title;
public string PublicationDate;
public string Description;
}
public class RssReader
{
public static List<RssNews> Read(string url)
{
var webResponse = WebRequest.Create(url).GetResponse();
if (webResponse == null)
return null;
var ds = new DataSet();
ds.ReadXml(webResponse.GetResponseStream());
var news = (from row in ds.Tables["item"].AsEnumerable()
select new RssNews
{
Title = row.Field<string>("title"),
PublicationDate = row.Field<string>("pubDate"),
Description = row.Field<string>("description")
}).ToList();
return news;
}
}
private string covertRss(string url)
{
var s = RssReader.Read(url);
StringBuilder sb = new StringBuilder();
foreach (RssNews rs in s)
{
sb.AppendLine(rs.Title);
sb.AppendLine(rs.PublicationDate);
sb.AppendLine(rs.Description);
}
return sb.ToString();
}
//Form Load code///
string readableRss;
readableRss = covertRss("http://ptwc.weather.gov/ptwc/feeds/ptwc_rss_indian.xml");
textBox5.Text = readableRss;
It seems that the DataSet.ReadXml method fails because there category is specified twice in the item, however under a different namespace.
This seems to work better:
public static List<RssNews> Read(string url)
{
var webClient = new WebClient();
string result = webClient.DownloadString(url);
XDocument document = XDocument.Parse(result);
return (from descendant in document.Descendants("item")
select new RssNews()
{
Description = descendant.Element("description").Value,
Title = descendant.Element("title").Value,
PublicationDate = descendant.Element("pubDate").Value
}).ToList();
}

Resources