I would like to send automatic email notifications to users after 30 days of inactivity.
For now i can send them manually (one by one), but this is time consuming.
How can i do it automatically, in the background?
Aspnet Core 6.0 C# + Bootstrap 5 + SQL Server
In my humble opinion, you need a trigger to help query inactive users and sent email to them at times. And I used to use Azure function time trigger to do it. And here's my test for your scenario.
Firstly, I have to expose API which is used to query the inactive users, and another one is used to send email.
public string sendEmail(string emailAddress) {
return "send to "+ emailAddress + " successfully";
}
public string queryInactive() {
return "user1#xx.com";
}
Then creating an Azure function time trigger to set it triggered every 9 am. Then write code to let the function call these 2 apis.
#r "Newtonsoft.Json"
using System;
using System.Net;
using System.Text;
using System.IO;
using System.IO.Compression;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Primitives;
using Newtonsoft.Json;
public static void Run(TimerInfo myTimer, ILogger log)
{
log.LogInformation($"C# Timer trigger function executed at: {DateTime.Now}");
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("https://xxxx/home/queryInactive");
request.Method = "GET";
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Stream myResponseStream = response.GetResponseStream();
StreamReader reader = new StreamReader(myResponseStream, Encoding.UTF8);
String userAddress = reader.ReadToEnd();
log.LogInformation(userAddress);
HttpWebRequest request2 = (HttpWebRequest)WebRequest.Create("https://xxxx/home/sendEmail?emailAddress="+userAddress);
request.Method = "GET";
HttpWebResponse response2 = (HttpWebResponse)request2.GetResponse();
Stream myResponseStream2 = response2.GetResponseStream();
StreamReader reader2 = new StreamReader(myResponseStream2, Encoding.UTF8);
String responseString = reader2.ReadToEnd();
log.LogInformation(responseString);
}
And this is my test result.
Related
I have a low-volume chat server. Some of the customers speak different languages so I have been using google translate and it had been working fine for years up to a couple weeks ago. I had been using a simple program like this:
// mcs -debug -out:TestTranslate.exe TestTranslate.cs
// mono --debug TestTranslate.exe
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using System.Web;
public class TestTranslate {
public static void Main (string[] args)
{
string apikey = "xxxxxxxxxxxxxxxxxxxxxxxxxxxx";
string message = "hello";
string srclc = "en";
string dstlc = "fr";
string query = "key=" + UrlEncode (apikey) +
"&q=" + UrlEncode (message) +
"&source=" + UrlEncode (srclc) +
"&target=" + UrlEncode (dstlc);
WebRequest request = WebRequest.Create ("https://www.googleapis.com/language/translate/v2?" + query);
request.Method = "GET";
request.Timeout = 3000;
string reply = new StreamReader (request.GetResponse ().GetResponseStream ()).ReadToEnd ();
Console.WriteLine (reply);
}
public static string UrlEncode (string text)
{
return text.Replace (" ", "+");
}
...but now it gets a '403' error. I suspect it is because I am not using OAuth2.0. I can't make any sense of the Google doc, it just goes round and round. Does anyone know how to make it work? I'm pretty sure I am using what they call 'service account', ie, one of my servers talking to one of their servers without any end-user authentication. I was able to download the OAuth2.0 json credential file. I would like to use C#/mono but Java is ok too.
With the help of claimprincipal, I'm able to get the details of signedin user as below but its not giving any pic related information as google does:
https://apis.live.net/v5.0/{USER_ID}/picture?type=large
which says The URL contains the path '{user_id}', which isn't supported.
Even tried
https://graph.microsoft.com/v1.0/me/photo/$value
which is asking for access token, but I am not sure what have to be passed
string userName = ClaimsPrincipal.Current.FindFirst("name").Value;
string userEmail = ClaimsPrincipal.Current.FindFirst(ClaimTypes.Email).Value;
string userId = ClaimsPrincipal.Current.FindFirst(ClaimTypes.NameIdentifier).Value;
Wanted an image which was added in any outlook account
For Image to show.. We have to use beared token and have to convert the image into memory stream and then have to used it.. I have done it in below ways. Hope this help ...
var client = new RestClient("https://login.microsoftonline.com/common/oauth2/token");
var request = new RestRequest(Method.POST);
request.AddHeader("cache-control", "no-cache");
request.AddHeader("content-type", "application/x-www-form-urlencoded");
request.AddParameter("application/x-www-form-urlencoded", $"code={code}&client_id={OutClientId}&client_secret={SecretKey}&redirect_uri={OutRedirectUrl}&grant_type=authorization_code", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
Token jsonContent = JsonConvert.DeserializeObject<Token>(response.Content);
var Token = jsonContent.AccessToken;
var TokenType = jsonContent.TokenType;
HttpClient httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", Token);
HttpResponseMessage response1 = await httpClient.GetAsync("https://graph.microsoft.com/v1.0/me/photos/96x96/$value");
if (response1.StatusCode == HttpStatusCode.OK)
{
using (Stream responseStream = await response1.Content.ReadAsStreamAsync())
{
MemoryStream ms = new MemoryStream();
responseStream.CopyTo(ms);
byte[] buffer = ms.ToArray();
string result = Convert.ToBase64String(buffer);
HttpContext.Session[AppConstants.UserImage] = String.Format("data:image/gif;base64,{0}", result);
responseStream.Close();
}
}
Is there any reason you are using the live.net apis? Instead of the Microsoft Graph APIs? Microsoft Graph APIs are the future for all user data within Microsoft 365 consumer and commercial accounts.
You can get the Users photo very easily as described here https://learn.microsoft.com/en-us/graph/api/profilephoto-get?view=graph-rest-1.0
GET /me/photo/$value
As you are using ASP.NET MVC, there is an SDK you can use that makes this very easy too.
https://learn.microsoft.com/en-us/graph/sdks/sdks-overview?context=graph%2Fapi%2F1.0&view=graph-rest-1.0
I got an assignment to see if I can make power app that will generate some PDF file for end user to see.
After through research on this topic I found out that this is not an easy to achieve :)
In order to make power app generate and download/show generated pdf I made these steps:
Created power app with just one button :) to call Azure function from step 2
Created Azure function that will generate and return pdf as StreamContent
Due to power app limitations (or I just could not find the way) there was no way for me to get pdf from response inside power app.
After this, I changed my Azure function to create new blob entry but know I have problem to get URL for that new entry inside Azure function in order to return this to power app and then use inside power app Download function
My Azure function code is below
using System;
using System.Net;
using System.Net.Http.Headers;
using System.Runtime.InteropServices;
using Aspose.Words;
public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log, Stream outputBlob)
{
log.Info($"C# HTTP trigger function processed a request. RequestUri={req.RequestUri}");
var dataDir = #"D:/home";
var docFile = $"{dataDir}/word-templates/WordAutomationTest.docx";
var uid = Guid.NewGuid().ToString().Replace("-", "");
var pdfFile = $"{dataDir}/pdf-export/WordAutomationTest_{uid}.pdf";
var doc = new Document(docFile);
doc.Save(pdfFile);
var result = new HttpResponseMessage(HttpStatusCode.OK);
var stream = new FileStream(pdfFile, FileMode.Open);
stream.CopyTo(outputBlob);
// result.Content = new StreamContent(stream);
// result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
// result.Content.Headers.ContentDisposition.FileName = Path.GetFileName(pdfFile);
// result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
// result.Content.Headers.ContentLength = stream.Length;
return result;
}
I left old code (the one that streams pdf back under comments just as reference of what I tried)
Is there any way to get download URL for newly generated blob entry inside Azure function?
Is there any better way to make power app generate and download/show generated PDF?
P.S. I tried to use PDFViewer control inside power app, but this control is completely useless cause U can not set Document value via function
EDIT: Response from #mathewc helped me a lot to finally wrap this up. All details are below.
New Azure function that works as expected
#r "Microsoft.WindowsAzure.Storage"
using System;
using System.Net;
using System.Net.Http.Headers;
using System.Runtime.InteropServices;
using Aspose.Words;
using Microsoft.WindowsAzure.Storage.Blob;
public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log, CloudBlockBlob outputBlob)
{
log.Info($"C# HTTP trigger function processed a request. RequestUri={req.RequestUri}");
var dataDir = #"D:/home";
var docFile = $"{dataDir}/word-templates/WordAutomationTest.docx";
var uid = Guid.NewGuid().ToString().Replace("-", "");
var pdfFile = $"{dataDir}/pdf-export/WordAutomationTest_{uid}.pdf";
var doc = new Document(docFile);
doc.Save(pdfFile);
var result = new HttpResponseMessage(HttpStatusCode.OK);
var stream = new FileStream(pdfFile, FileMode.Open);
outputBlob.UploadFromStream(stream);
return req.CreateResponse(HttpStatusCode.OK, outputBlob.Uri);
}
REMARKS:
Wee need to add "WindowsAzure.Storage" : "7.2.1" inside project.json. This package MUST be the same version as one with same name that is in %USERPROFILE%\AppData\Local\Azure.Functions.Cli
If you change your blob output binding type from Stream to CloudBlockBlob you will have access to CloudBlockBlob.Uri which is the blob path you require (documentation here). You can then return that Uri back to your Power App. You can use CloudBlockBlob.UploadFromStreamAsync to upload your PDF Stream to the blob.
I have a sql query that is generating a list of order numbers...I can place these order numbers individually in the web request URL to Web Services and collect the details of that order. I know how to do that if I had a WSDL file available but the We services is using a RestFul service client and has no WSDL file. I do have a C# code that will work only if I declare the order number and was trying to find out how can I replace this parameter with a DTS variable and use a Foreach loop container to run the rest of the order numbers in the list. Here's the code that I have so far:
using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.IO;
using System.Net;
using System.Xml;
/**
* A test code to consuming a RESTFUL web service.
* You need to just parse the xml - either save it in memory/Cache to parse immediatly,
* or wrire to file and do read and parse it.
* #author: Jbisht
*/
namespace JbishtApplication
{
class CallWeb
{
static void Main(string[] args)
{
HttpWebRequest request = null;
HttpWebResponse response = null;
String Xml;
String salesOrderNo = "S3107634";
String file_ext = ".xml";
String file_name = salesOrderNo + file_ext;
String file_path = "C:/";
// Create the web request - Zones Test Environment - Orderws URL
// request = WebRequest.Create("http://test2:8080/orderws/order/" + salesOrderNo) as HttpWebRequest;
// Create the web request - My instance - Orderws for test only
request = WebRequest.Create("http://dev2:10580/orderws/order/" + salesOrderNo) as HttpWebRequest;
// Get response
using (response = request.GetResponse() as HttpWebResponse)
{
// Get the response stream
StreamReader reader = new StreamReader(response.GetResponseStream());
Xml = reader.ReadToEnd();
XmlDocument xdoc = new XmlDocument();
xdoc.LoadXml(Xml);
xdoc.Save(file_path + file_name); // it will save your response xml to file location;
}
// Console xml output
Console.WriteLine(Xml); //see if we get the xml response, (YES we do)
Console.ReadLine(); // Just wrote to keep console window open after writing to console.
}
}
}
In general, you will need a SQL task as the starting point which gets the list of order numbers from database, and saves query result into a variable of Object type, say "OrderNumberList". Then you have a foreach loop container to loop through the "OrderNumberList" variable, and assigning the current value into another variable "OrderNumber".
(If you have not done all of these before, HERE is a link shows how to loop through a database query result set.)
Place a Script task inside the foreach container, and choose "OrderNumber" as readonly variable, so you can reference the variable in the script. Then in the script, "OrderNumber" can be referenced as:
request = WebRequest.Create("http://dev2:10580/orderws/order/" +
((string) Dts.Variables["OrderNumber"].Value)) as HttpWebRequest;
I need to check if a webpage exists if it does whether a certain string exists anywhere on the page.
Preferably I'd like to do this without a webbrowser control, so that images don't have to be downloaded and it doesn't have to be rendered.
So is there a way to do this?
First, follow the instructions here (Though, the instructions are in C#, they should easily be converted to VB.)
using System.Text;
using System.Net;
using System.IO;
HttpWebRequest myRequest = (HttpWebRequest)WebRequest.Create(URL);
myRequest.Method = "GET";
WebResponse myResponse = myRequest.GetResponse();
StreamReader sr = new StreamReader(myResponse.GetResponseStream(), System.Text.Encoding.UTF8);
string result = sr.ReadToEnd();
sr.Close();
myResponse.Close();
Now, once you have this, perform the search on result string
Dim stringFound = result.IndexOf("My search string")