C# .net-core Web API Serilog: log files to different folders based on property (i.e. controller name) - asp.net-core-webapi

Our client wants log files stored in separate folders based on the controller. For example, all logs that hit the Shipping controller would be stored in C:\logs\shipping\ while those that hit the orders controller would be in c:\logs\orders and so on. Below is my ConfigureLoggingServices method. I'm using Serilog and writing to a file and to Seq. I'm using middleware to capture the client user and session ID (stored in the request header) and pushing these values to the log entry with LogContext.PushProperty(). I somehow need to inject the name of the controller into the path of the log file. Is this possible? Thanks
private void ConfigureLoggingServices()
{
var appName = Configuration.GetValue<string>("Logging:AppName", string.Empty);
var SeqURL = Configuration.GetValue<string>("Logging:SeqURL", string.Empty);
var pool = Environment.UserName;
//string logFile = "C:\\Logs\\" + {Controller} + "\\lis_api.log";
string logFile = "C:\\Logs\\lis_api.log";
const string customTemplate = "[{LIS_User} {Timestamp:HH:mm:ss.fff} {Level:u3} {SessionID}] {RequestMethod} {RequestPath} {Message:lj}{NewLine}{Exception}";
var name = Assembly.GetExecutingAssembly().GetName();
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Debug()
.MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
.MinimumLevel.Override("System", LogEventLevel.Warning)
.Enrich.FromLogContext()
.Enrich.WithMachineName()
.Enrich.WithProperty("Application", appName)
.Enrich.WithProperty("Version", $"{name.Version}")
.Enrich.WithProperty("AppPool", pool)
.Destructure.ByTransforming<User>(x => new { x.ID, x.Name, x.Controller })
// File Sink - Async
.WriteTo.Async(a => a.
File(string.Format(string.Format(logFile)),
rollingInterval: RollingInterval.Day,
outputTemplate: customTemplate,
fileSizeLimitBytes: 40000000,
shared: true,
retainedFileCountLimit: 50,
rollOnFileSizeLimit: true))
.WriteTo.Seq(SeqURL)
.CreateLogger();
LoggerFactory = CreateLoggerFactory();
}

.WriteTo.Map(
"Controller",
"(None)",
(ctrl, wt) => wt.File($"C:\\Logs\\{ctrl}\\lis_api.log"))

Related

Xamarin Forms: Get the path of an image file stored on the shared project?

I am trying to upload an image file as ByteArrayContent through my web service. I have added all the images to the shared project and set the build action as Embedded resource.
Following is my code:
var fileBytes = File.ReadAllBytes("Avatars." + selectedAvatar);
var byteContent = new ByteArrayContent(fileBytes);
content.Add(byteContent, "file", selectedAvatar);
When I try like above I am getting System.IO.FileNotFoundException: Could not find file "/Projectname.Avatars.ic_avatar01_xx.png"
Added the images directly inside a folder in the shared project like the below screenshot.
:
I tried changing the . with a / in the file path, like below:
var fileBytes = File.ReadAllBytes("Avatars/" + selectedAvatar);
var byteContent = new ByteArrayContent(fileBytes);
content.Add(byteContent, "file", selectedAvatar);
But in that case, I am getting the System.IO.DirectoryNotFoundException: Could not find a part of the path "/Avatars/ic_avatar01_xx.png"
What is the correct way to get the path of an image file stored on a shared project?
Also tried another approach:
string avatarFileName = "Avatars/" + selectedAvatar;
var assembly = typeof(ProfilePage).GetTypeInfo().Assembly;
var stream = assembly.GetManifestResourceStream($"{assembly.GetName().Name}.{avatarFileName}");
content.Add(stream, "file", avatarFileName);
But in the above case I am getting the below error:
If you want to upload the image with Stream , you could check the following code
private async Task<string> UploadImage(Stream FileStream)
{
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://your.url.com/");
MultipartFormDataContent form = new MultipartFormDataContent();
HttpContent content = new StringContent("fileToUpload");
form.Add(content, "fileToUpload");
content = new StreamContent(FileStream);
content.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{
Name = "fileToUpload",
FileName = "xxx.png"
};
form.Add(content);
var response = await client.PostAsync("http://your.url.com/", form);
return response.Content.ReadAsStringAsync().Result;
}
Option 2:
You could also use the plugin FileUploaderPlugin . It support uploading multiple files at once
Uploading from a file path
CrossFileUploader.Current.UploadFileAsync("<URL HERE>", new FilePathItem("<REQUEST FIELD NAME HERE>","<FILE PATH HERE>"), new Dictionary<string, string>()
{
{"<HEADER KEY HERE>" , "<HEADER VALUE HERE>"}
}
);
Option 3:
The first parameter of MultipartFormDataContent is HttpContent. To handle the stream, try using the StreamContent type which inherits from the HttpContent. Get the streamContent from the stream and add id to the MultipartFormDataContent.
string avatarFileName = "Avatars." + selectedAvatar;
var assembly = typeof(ProfilePage).GetTypeInfo().Assembly;
var stream = assembly.GetManifestResourceStream($"{assembly.GetName().Name}.{avatarFileName}");
var streamContent = new StreamContent(stream);
content.Add(streamContent, "file", avatarFileName);

Is it possible to create a folder on the Alfresco site by using OpenCMIS API?

I have the Presentation Web Script (script A) and the Data Web Script (script B).
In the script A I build the dialog that interacts with the script B.
Here I am forming some path where the some file will be uploaded (group, year and number parameters define this path):
...
var submitHandler = function() {
var dataWebScriptUrl = window.location.protocol + '//' +
window.location.host + "/alfresco/s/ms-ws/script-b?guest=true";
var yearCombo = document.getElementById("year");
var year = yearCombo.options[yearCombo.selectedIndex].value;
var groupCombo = document.getElementById("group");
var group = groupCombo.options[groupCombo.selectedIndex].value;
var numberCombo = document.getElementById("number");
var number = numberCombo.value;
var uploadedFile = document.getElementById("uploadedFile");
var file = uploadedFile.files[0];
var formData = new FormData();
formData.append("year", year);
formData.append("group", group);
formData.append("number", number);
formData.append("uploadedFile", file);
var xhr = new XMLHttpRequest();
xhr.open("POST", dataWebScriptUrl);
xhr.send(formData);
};
...
In script B, I'm using the Apache Chemistry OpenCMIS API to create a path in the CMIS-compatible Alfresco repository:
public class CustomFileUploader extends DeclarativeWebScript implements OpenCmisConfig {
...
private void retrievePostRequestParams(WebScriptRequest req) {
String groupName = null, year = null, number = null;
FormData formData = (FormData) req.parseContent();
FormData.FormField[] fields = formData.getFields();
for(FormData.FormField field : fields) {
String fieldName = field.getName();
String fieldValue = field.getValue();
if(fieldName.equalsIgnoreCase("group")) {
if(fieldValue.equalsIgnoreCase("services")) {
groupName = "Услуги";
...
}
firstLevelFolderName = "/" + groupName;
secondLevelFolderName = groupName + " " + year;
thirdLevelFolderName = number;
}
...
Folder firstLevelFolder =
createFolderIfNotExists(cmisSession, docLibFolder, firstLevelFolderName);
...
private Folder createFolderIfNotExists(Session cmisSession,
Folder parentFolder, String folderName) {
Folder subFolder = null;
for(CmisObject child : parentFolder.getChildren()) {
if(folderName.equalsIgnoreCase(child.getName())) {
subFolder = (Folder) child;
}
}
if(subFolder == null) {
Map<String, Object> props = new HashMap<>();
props.put("cmis:objectTypeId", "cmis:folder");
props.put("cmis:name", folderName);
subFolder = parentFolder.createFolder(props);
}
return subFolder;
}
private Folder getDocLibFolder(Session cmisSession, String siteName) {
String path = "/Sites/" + siteName + "/documentLibrary";
return (Folder) cmisSession.getObjectByPath(path);
}
private Session getCmisSession() {
SessionFactory factory = SessionFactoryImpl.newInstance();
Map<String, String> conf = new HashMap<>();
// http://localhost:8080/alfresco/api/-default-/public/cmis/versions/1.1/atom
conf.put(SessionParameter.ATOMPUB_URL, ATOMPUB_URL);
conf.put(SessionParameter.BINDING_TYPE, BindingType.ATOMPUB.value());
conf.put(SessionParameter.USER, USER_NAME);
conf.put(SessionParameter.PASSWORD, PASSWORD);
// "org.alfresco.cmis.client.impl.AlfrescoObjectFactoryImpl"
conf.put(SessionParameter.OBJECT_FACTORY_CLASS, OBJECT_FACTORY_CLASS);
conf.put(SessionParameter.REPOSITORY_ID, "-default-");
Session session = factory.createSession(conf);
return session;
}
...
It's all works well... But I need to create the directory structure on a specific site, e.g. "contracts-site", here:
/site/contracts-site/documentlibrary
When I specifying the following:
/Sites/contracts-site/documentLibrary/Услуги
/Sites/contracts-site/Услуги
/site/contracts-site/documentlibrary/Услуги
I get the following exception (depending on the path):
org.apache.chemistry.opencmis.commons.exceptions.CmisObjectNotFoundException: Object not found: /Sites/contracts-site/Услуги
When I specifying the following:
"/Услуги"
Everything works, but the directory structure is created outside the site...
How to create a folder on the Alfresco site by using OpenCMIS API?
Arn't you missing /company_home/ ?
This would lead to
/company_home/Sites/contracts-site/documentLibrary/Услуги
Just accidentally found the solution. Works perfectly if specify the following path:
// locate the document library
String path = "/Сайты/contracts-site/documentLibrary";
Ie, "Сайты" instead of "Sites"... (Cyrillic alphabet)
I'm using ru_RU locale and UTF-8 encoding. Then this example also works.

Save a document in Alfresco shared folder via Rest API

I'm try to upload a file to the shared folder...
This is my code.
// using httpclient-4.5
Path filePath = Paths.get("C:/afile.txt");
String ticket = getTicket(); // get a ticket via /alfresco/service/api/login...
CloseableHttpClient client = HttpClients.createDefault();
HttpPost post = new HttpPost("http://localhost:8080/alfresco/service/api/upload?alf_ticket=" + ticket);
MultipartEntityBuilder entity = MultipartEntityBuilder.create();
StringBody descriptionBody = new StringBody("a test", ContentType.TEXT_PLAIN);
StringBody siteId = new StringBody("company_home", ContentType.TEXT_PLAIN); // how can upload the file
StringBody containerid = new StringBody("/Shared", ContentType.TEXT_PLAIN); // in the shared folder??
entity.addBinaryBody("filedata", filePath.toFile());
entity.addPart("siteid", siteId);
entity.addPart("containerid", containerid);
post.setEntity(entity.build());
CloseableHttpResponse postResponse = client.execute(post);
// ...
Can anyone help me? Thanks.

Dynamically create folder when user first time accessing url asp.net mvc4

I want to create folder when user first time accessing url, for this I created this code to create such a folder in my application start file (global.aspx.cs). But problem is folder is only created one time, when two users access the url from different ip but folder is common.
AreaRegistration.RegisterAllAreas();
const string Chars = "ABCDEFGHIJKLMNPOQRSTUVWXYZ0123456789";
var random = new Random();
var result = new string(
Enumerable.Repeat(Chars, 12)
.Select(s => s[random.Next(s.Length)])
.ToArray());
var path = Server.MapPath("~/App_Data/" + result);
Directory.CreateDirectory(path);
Application["Path"] = Server.MapPath("~/App_Data/" + result);
This problem you are facing because one Application variable will be formed for all users visiting your website,if you want different folders for different user you have to make sessions,because session will be different for different user in Application_AcquireRequestState event..
protected void Application_AcquireRequestState(object sender, EventArgs e)
{
HttpContext context = HttpContext.Current;
const string Chars = "ABCDEFGHIJKLMNPOQRSTUVWXYZ0123456789";
var random = new Random();
var result = new string(
Enumerable.Repeat(Chars, 12)
.Select(s => s[random.Next(s.Length)])
.ToArray());
var path = Server.MapPath("~/App_Data/" + result);
Directory.CreateDirectory(path);
// Application["Path"] = Server.MapPath("~/App_Data/" + result);
context.Session["Path"] = Server.MapPath("~/App_Data/" + result);
}
Now in your entire application you can access HttpContext.Session["Path"] for the current user.

Modify contents of static files

how can I modify the response before it is sent to the client when I use Microsoft.Owin.StaticFiles?
FileServerOptions options = new FileServerOptions();
options.FileSystem = new Microsoft.Owin.FileSystems.PhysicalFileSystem(Path.Combine(Environment.CurrentDirectory, "Content/"));
options.DefaultFilesOptions.DefaultFileNames = new string[] { "index.htm", "index.html" };
options.StaticFileOptions.OnPrepareResponse = (r) =>
{
r.OwinContext.Response.WriteAsync("test");
};
options.EnableDefaultFiles = true;
app.UseFileServer(options);
"test" is never written into the response. I tried to use another middleware which waits until the StaticFiles Middleware is executed:
app.Use((ctx, next) =>
{
return next().ContinueWith(task =>
{
return ctx.Response.WriteAsync("Hello World!");
});
});
FileServerOptions options = new FileServerOptions();
options.FileSystem = new Microsoft.Owin.FileSystems.PhysicalFileSystem(Path.Combine(Environment.CurrentDirectory, "Content/"));
options.DefaultFilesOptions.DefaultFileNames = new string[] { "index.htm", "index.html" };
options.EnableDefaultFiles = true;
app.UseFileServer(options);
But this didn't work. How can I modify the response?
On prepare response is not meant to modify the content of a static file.
You are only allowed to add the header.
I needed to pass some variable that change to a static web page and I got around it by using
On prepare response and passed the variables as cookies for the page.
This works nicely for a few variables but if you want to change a page significantly you are better of using mvc components.
appBuilder.UseStaticFiles(new StaticFileOptions()
{
RequestPath = new PathString(baseUrl),
FileSystem = new PhysicalFileSystem(staticFilesLocation),
ContentTypeProvider = new JsonContentTypeProvider(),
OnPrepareResponse = r => r.OwinContext.Response.Cookies.Append("baseUrl",_webhostUrl)
});

Resources