I want to write to a log file in an Elsa workflow. I was wondering if someone has an example of how they were able to write to a log file in an Elsa workflow. I was trying to use the OutFile activity, but I am wondering if someone has an example of writing to a file using this activity or if there is another option to write to a log file in an Elsa workflow
I found the best way to handle this was to create a custom activity in code. Here is the class that was created:
[Action(
Category = "File",
DisplayName = "Write to File",
Description = "Writes text to a file")]
public class WriteToFile : Activity
{
[Required]
[ActivityInput(Hint = "Text to write to file.", UIHint = ActivityInputUIHints.SingleLine, SupportedSyntaxes = new[] { SyntaxNames.JavaScript, SyntaxNames.Liquid })]
public string Text { get; set; } = default!;
[Required]
[ActivityInput(Hint = "Path of the file to write to.", UIHint = ActivityInputUIHints.SingleLine, SupportedSyntaxes = new[] { SyntaxNames.JavaScript, SyntaxNames.Liquid })]
public string FilePath { get; set; } = default!;
[ActivityInput(Hint = "How to handle an existing file.", UIHint = ActivityInputUIHints.Dropdown, DefaultValue = CopyMode.Append)]
public CopyMode Mode { get; set; }
public override async ValueTask<IActivityExecutionResult> ExecuteAsync(ActivityExecutionContext context)
{
using (StreamWriter file = new(FilePath, append: Mode == CopyMode.Append))
{
await file.WriteLineAsync(Text);
};
return Done();
}
}
Related
My AppConfig.json:
{
"MyTimeZone: "CET",
"RegularString" : "SomeValue",
"AnArray" : ["1","2"]
}
My POCO class:
public class Settings
{
public TimeZoneInfo MyTimeZone { get; set; }
public string RegularString { get; set; }
public IList<string> AnArray { get; set; }
}
Registry.cs:
var configuration = GetConfiguration("AppSettings.json");
services.Configure<Settings>(configuration.GetSection("Settings"));
This of course does not bind "CET" into a valid TimeZoneInfo object. Now the question is what is the best place in my application (a web app) to convert from string to TimeZoneInfo? Is there a way to automatically convert string config values to objects based on certain rules without creating custom converters?
Reference Use DI services to configure options
services.AddOptions<Settings>()
.Configure<IConfiguration>((setting, configuration) => {
var section = config.GetSection("Settings");
//This will populate the other properties that can bind by default
section.Bind(setting);
//this will extract the remaining value and set it mnually
string value = section.GetValue<string>("MyTimeZone");
TimeZoneInfo info = TimeZoneInfo.FindSystemTimeZoneById(value);
setting.MyTimeZone = info;
});
The complex setting value can be extracted directly from configuration via DI and used to create the time zone and apply it to the settings.
It just my personal opinion but I prefer the MyTimeZone to be a json object instead only a string. Consider the following:
"Settings": {
"MyTimeZone": {
"ConfigureTimeZoneById": "CET"
},
"RegularString": "SomeValue",
"AnArray": [ "1", "2" ]
}
MyTimeZone.ConfigureTimeZoneById is not part of the actual data object. It's just proxy to bind object to configuration. This how TimeZone class might look like:
public class TimeZone
{
private string configureTimeZoneById { get; set; }
public string ConfigureTimeZoneById
{
get { return configureTimeZoneById; }
set
{
configureTimeZoneById = value;
InitializeTimeZone(value);
}
}
public string TimeZoneId { get; set; }
public string OtherProperties { get; set; }
private void InitializeTimeZone(string id)
{
var getTimeZone = TimeZonesDataset().FirstOrDefault(tzon => tzon.TimeZoneId.Equals(id));
if (getTimeZone != null)
{
this.TimeZoneId = getTimeZone.TimeZoneId;
this.OtherProperties = getTimeZone.OtherProperties;
}
}
//dummy dataset
private List<TimeZone> TimeZonesDataset() => new List<TimeZone> {
new TimeZone{TimeZoneId = "CET", OtherProperties = "Dummy properties to prove point"},
new TimeZone{TimeZoneId = "GMT", OtherProperties = default},
};
With this DTO:
public class QuestionDTO {
public Guid Id { get; set; }
public string Prompt { get; set; }
public List<Answer> Choices { get; set; }
public QuestionDTO() {
}
public QuestionDTO(Question question) {
this.Id = question.Id;
this.Prompt = question.Prompt;
this.Choices = question.Choices;
}
}
I was getting an error about Unable to Parse without a parameterless constructor. I have since fixed that, but now my objects are de-serialized empty:
using System.Text.Json;
var results = JsonSerializer.Deserialize<List<QuestionDTO>>(jsonString);
The jsonString contains 3 items with the correct data, and the deserialized list contains 3 items, but all the properties are empty.
The new json library is case sensitive by default. You can change this by providing a settings option. Here is a sample:
private JsonSerializerOptions _options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }
private async Task SampleRequest()
{
var result = await HttpClient.GetStreamAsync(QueryHelpers.AddQueryString(queryString, queryParams));
_expenses = await JsonSerializer.DeserializeAsync<List<Common.Dtos.Expenses.Models.Querys.ExpensesItem>>(result, _options);
}
I'm trying to upload file (just .jpeg image) and save it on my server. I've written the following code for this:
Db context
public class ApplicationContext : DbContext
{
private readonly string _connectionString;
public ApplicationContext(IConfiguration configuration)
{
_connectionString = configuration.GetConnectionString("Recipes");
}
public DbSet<FileModel> Files { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseNpgsql(_connectionString);
}
}
Model
public class FileModel
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string Name { get; set; }
public string Path { get; set; }
}
Method of my controller for uploading
public async Task<IActionResult> AddFile(IFormFile uploadedFile)
{
string path = "";
if (uploadedFile != null)
{
// путь к папке Files
path = "/Files/" + uploadedFile.FileName;
using (var fileStream = new FileStream(_appEnvironment.WebRootPath + path, FileMode.Create))
{
await uploadedFile.CopyToAsync(fileStream);
}
FileModel file = new FileModel { Name = uploadedFile.FileName, Path = path };
_applicationContext.Files.Add(file);
_applicationContext.SaveChanges();
}
The the next step that I'm going to do is testing it with the help of Insomnia rest client. I had setted up all acording to Insomnia documentation (to passing multipart/form-data header) and sent request. But in the uploadedFile I see null.
Here is screenshot of Insomnia
And screen of the result:
Why uploadedFile is null? Where is the mistake?
Parameter name in your client is image not expected uploadedFile defined in Controller action
I am Beginner at Asp.net so can anyone plz help me to show the data provided in the below shown JSON Api in Asp.net Step by Step.It be of great help if this is answered.
http://fantasy.premierleague.com/web/api/elements/180/
A good way to use Json in C# is with Json.NET
JSON.NET - Official site will help you work with it.
Example to use it
public class User {
public User(string json) {
JObject jObject = JObject.Parse(json);
JToken jUser = jObject["user"];
name = (string) jUser["name"];
teamname = (string) jUser["teamname"];
email = (string) jUser["email"];
players = jUser["players"].ToArray();
}
public string name { get; set; }
public string teamname { get; set; }
public string email { get; set; }
public Array players { get; set; }
}
// Use
private void Run() {
string json = #"{""user"":{""name"":""asdf"",
""teamname"":""b"",""email"":""c"",""players"":[""1"",""2""]}}";
User user = new User(json);
Console.WriteLine("Name : " + user.name);
Console.WriteLine("Teamname : " + user.teamname);
Console.WriteLine("Email : " + user.email);
Console.WriteLine("Players:");
foreach (var player in user.players)
Console.WriteLine(player);
}
In my application i will have dynamic rss feed url saved by users. so i want to know that how can i read that xml which will be returned by rss feed. what will be the structure of that xml ? I have reviewed some feed url and i noticed that most of them have title and description tags but i am not sure to this. if i get these two tags then i will parse xml but if they are not always available then how can i parse xml in that case.
these two contains title and description tag
http://rss.news.yahoo.com/rss/entertainment
http://xml.weather.yahoo.com/forecastrss?p=USCA1116
At first you need to read a XML file for that I recommend you to use XPath or Linq to XML, and as you already said there are three main elements that make up a feed; "title", "link" and "description".
Not a very long time ago I wrote a code to do that, I hope this works for you.
I created this two entities.
public class RssFeed
{
public string Title { get; set; }
public string Link { get; set; }
public string Description { get; set; }
public string PubDate { get; set; }
public string Language { get; set; }
public ObservableCollection<RssItem> RssItems { get; set; }
}
public class RssItem
{
public string Title { get; set; }
public string Description { get; set; }
public string Link { get; set; }
}
Then on this method I read every element from the XML file by using Linq to XML
private static void ReadFeeds()
{
string uri = #"http://news.yahoo.com/rss/entertainment";
WebClient client = new WebClient();
client.DownloadStringAsync(new Uri(uri, UriKind.Absolute));
client.DownloadStringCompleted += (s, a) =>
{
if (a.Error == null && !a.Cancelled)
{
var rssReader = XDocument.Parse(a.Result);
var feed = (from rssFeed in rssReader.Descendants("channel")
select new RssFeed()
{
Title = null != rssFeed.Descendants("title").FirstOrDefault() ?
rssFeed.Descendants("title").First().Value : string.Empty,
Link = null != rssFeed.Descendants("link").FirstOrDefault() ?
rssFeed.Descendants("link").First().Value : string.Empty,
Description = null != rssFeed.Descendants("description").FirstOrDefault() ?
rssFeed.Descendants("description").First().Value : string.Empty,
PubDate = null != rssFeed.Descendants("pubDate").FirstOrDefault() ?
rssFeed.Descendants("pubDate").First().Value : string.Empty,
Language = null != rssFeed.Descendants("language").FirstOrDefault() ?
rssFeed.Descendants("language").First().Value : string.Empty
}).Single();
var rssFeeds = (from rssItems in rssReader.Descendants("item")
select new RssItem()
{
Title = null != rssItems.Descendants("title").FirstOrDefault() ?
rssItems.Descendants("title").First().Value : string.Empty,
Link = null != rssItems.Descendants("link").FirstOrDefault() ?
rssItems.Descendants("link").First().Value : string.Empty,
Description = null != rssItems.Descendants("description").FirstOrDefault() ?
rssItems.Descendants("description").First().Value : string.Empty,
}).ToList();
feed.RssItems = new ObservableCollection<RssItem>(rssFeeds);
}
};
}
And finally you have your feed to be displayed wherever you want.