How to reference a file inside class library - c#

I have this code in my asp.net app:
String appPath = HttpContext.Current.Request.MapPath(HttpContext.Current.Request.ApplicationPath);
String path = appPath + "\\Database\\SAMPLE.BIN";
I want to movie it to a class library, which then will be referenced by multiple projects.
The thing is that HttpContext.Current.Request.ApplicationPath is referencing the running app and not the class lib.
How do I put the SAMPLE.BIN inside the class lib, so that I don't have to duplicate it in all referencing projects?
EDIT:
At the end I need to be able to:
myobject.DatabasePath = appRoot + "\\Database\\SAMPLE.BIN";

You have 2 choices:
Either you pass the value as a parameter to your new library:
public class MyNewLibrary {
private string _path { get; set; }
public MyNewLibrary(string path)
{
this.path = path;
}
}
or you import the System.Web reference and use the HttpContext at will.

Related

How to create an error report and Log that contains information from all libraries using .Net Framework (C#)

I am about to create some library that contains all common functions I used in my projects. (Opening File Dialogs, reading spreadsheets, etc..)
And I am planning to use it when I develop some Form application. All my classes are static in that library project.
Here is a example scenario:
I wrote Library.dll and add it to my Form project as reference. I am always using Console.Writeline() to watch what happened in my code. So I did the same in Library.dll.Lets say I have LibraryClass.cs in my Library.dll And when I call a function from that class to Form project I can not see the Console logs inside of that function.
I create another static class at my library called Report.cs. It creates 2 different type of lists. First one is a string list, and using instead of Console.WriteLine(), I am using this string list. I am using Report.WriteLine() function to add strings inside of that string list. It helps me the collect all the logs that I wrote in Form and also in Library.
The second one is a Record object that I created. It contains information like "Code", "Info", "Title" "Reference", "Type" as properties. Type property allows me to define record as an "Error" or "Warning" or just a "Record". If I can catch an error from catch statement or some warning, I am creating an Record object that contains information I mentioned and I am adding it to that Record list in Report.cs. But I am pretty sure there is a more efficient way to do that.
Here is my Record Object:
public class ReportElement
{
public string Info { get; set; }
public string Title { get; set; }
public DateTime Time;
public string Reference { get; set; }
public string Code { get; set; }
public List<string> Targets { get; set; }
public string Log { get; }
public ReportElementType Type { get; set; }
public ReportElement(string code, string info, string title, ReportElementType reportElementType = ReportElementType.kJournal, string reference = null, List<string> targets = null)
{
this.Info = info;
this.Title = title;
this.Time = DateTime.Now;
this.Code = code;
this.Type = reportElementType;
this.Targets = targets;
this.Reference = reference;
this.Log = this.CreateLogString();
Report.WriteLine(this.Log);
}
public enum ReportElementType
{
kError = 0,
kWarning = 1,
kJournal = 2
}
}
And I am collecting that elements in my Report Class inside of a List:
private static List<ReportElement> RecordedReportElements = new List<ReportElement>();
List of logs(Also in report class:
public static List<string> ListLog = new List<string>();
And I am writing strings in that list with that function:
public static void WriteLine(string Text, bool WithTimer = true)
{
try
{
string logString = WithTimer? Text + " | " + GetTimerValue():Text;
ListLog.Add(logString);
Console.WriteLine(logString);
}
catch (Exception e)
{
Console.WriteLine("Can not be saved in List Log : " + Text);
Console.WriteLine(e.Message);
}
}
At the end I can use this library in any other project like this:
Report.WriteLine("MY LOG STRING")
ReportElement NewElement = new ReportElement(Code, Info, Title, ReportElementType, Reference, Targets);
Report.RecordedReportElements.Add(NewELement)
So the summary of the things I need to achieve:
Creating an journal mechanic ( The list that contains all the record object that i created.)
Collect all console logs from the library I used and form application I am developing.
If some error happens at my library, my library also have to be able to terminate my form application.
After termination I want to be able to make some report visible.(as .txt or .xlsx or as an another form)
So at the end anyone has better strategy to do that or some documentation that explains how to catch errors, and create a report after the process done or terminate.
Thanks.

How to get current folder from a C# static class on Unity

I imported a Unity package where several Editor scripts depend on a RootPath property from a static class:
public static class EditorUtils
{
public static string RootPath => "Assets/HardcodedPath";
}
The problem is that this path is hardcoded, so that the package location can't be changed at all. I plan on changing the RootPath property so that it gets the current script location and searches for parent folder with a given pattern. That way, I would be able to use this package even inside a custom package of my own (inside a Packages folder instead of the Assets folder, that is).
The missing piece is that I can't find a way to get this static class folder location from code. Can anyone help me with this?
Dig around through the AssetDatabase and find a reference to your script. This should return what you're wanting.
public static class EditorUtils
{
public static string RootPath
{
get
{
var g = AssetDatabase.FindAssets ( $"t:Script {nameof(EditorUtils)}" );
return AssetDatabase.GUIDToAssetPath ( g [ 0 ] );
}
}
}
That will also hold true for scripts in Packages.
Remember to change EditorUtils to your script name.
Here's the relevant Unity docs.

Is there a way to load object data in void Load() without assigning each property separately (C#)?

I'm working on a small WPF app to help me with file organisation. The class I store most of my data in is Project and it contains most of the data the app uses. Therefore, it has a lot of properties which I need to be saved and loaded from a file (around 20, using few as an example)
public DateTime Start { get; set; }
public DateTime End { get; set; }
public Int32 Count { get; set; }
public String Name { get; set; }
public HashSet<String> Files { get; set; }
As far as I know, loading an object can be done in 2 main ways:
I.
Project.cs
public Project Load( String file ) {
Project project = json( file ); //to shorten the question
return project;
}
MainWindow
Project project = new Project();
project = project.Load( file );
II.
Project.cs
public void Load( String file ) {
Project project = json( file );
Start = project.Start;
End = project.End;
Count = project.Count;
Name = project.Name;
Files = project.Files;
}
MainWindow
Project project = new Project();
project.Load( file );
Can I somehow still use void Load() function, but assign the whole object at once?
I tried using this = project;, but it is read-only.
Json .net has a method,
Quick and dirty way to do it using reflection
var project = Json(file); //to shorten the question
foreach (var prop in this.GetType().GetProperties())
{
prop.SetValue(this, prop.GetValue(project));
}
return project;
More performant way using compilation this one is more advanced.
But this looks like somewhat wrong in general when using wpf you should be using some MVVM pattern and the project should be the binding context of your view and you can set the created object from json with out making a copy of the object.

App config in Class library C#

I have a wpf application which is using a dll of a class library. I am unable to access the app.config value in the class library
How I'm trying to access app.config:
ConfigurationSettings.AppSettings["conStr"].ToString();
this is returning a null value
using System.Configuration is also added .
Why don't you just put that value in the Main Project ?
If you're calling the class library from the Main Project. Then the code in the class library uses the AppConfig defined inside the main project.
It is a common practice to have the connection string in the AppConfig for the Main Project and not inside the Class Library.
I recomend to use your own class for save Class Library settings. Something like this:
public class GlobalSettings
{
public double RedFiber { get; set; }
public double GreenFiber { get; set; }
public double BlueFiber { get; set; }
public bool DeleteMinorViews { get; set; }
public static GlobalSettings Load()
{
try
{
return JsonConvert.DeserializeObject<GlobalSettings>(File.ReadAllText(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\YOUR_APP_NAME\\"));
}
catch ()
{
return DefaultSettings;
}
}
public void Save()
{
File.WriteAllText(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\YOUR_APP_NAME\\", JsonConvert.SerializeObject(this, Formatting.Indented));
}
private static readonly GlobalSettings DefaultSettings = new GlobalSettings()
{
RedFiber = 0,
GreenFiber = 255,
BlueFiber = 0,
DeleteMinorViews = true,
};
}
I had the same issue. Try adding a settings file for your class library to store your values. The value will be stored in the app.config but accessed using the settings file.
This post explains better: Can a class library have an App.config file?
This post goes into more detail about settings files: Best practice to save application settings in a Windows Forms Application
If you prefer not to do the above you can also move your data to the main projects App.config file and it should work.
try
ConfigurationManager.AppSettings["conStr"].ToString();
If the does not work post your App.Config
ConfigurationSettings.AppSettings is obsolete

EF entity, local file as property

I have an entity that has both general properties that are stored in database table and a reference to a local file on system disk. I want the create/replace/delete methods for this file be encapsulated in the data access layer to let other parts of the application not care of how and where it should be stored, just send a bytes stream of perform "clear" operation. At the same time, I'd like the file directory to be defined in web.config like database access parameters are.
Im my web app I use EF 5 Code First and have defined the entity like an example below:
// EF entity
public class UserImage{
public string Description { get; set; }
[NotMapped]
public LocalFile File { get; set; }
}
// not EF entity
public class LocalFile{
public string Name { get; set; }
public string LocalPath { // should return full path as dir path + file name }
public string Url { // should return LocalPath mapped to Url }
public void Set(FileStream fs) { // saves file to disk }
public void Clear() { // deletes file }
}
In my approach I can account my DbContext is not only database context, but a context for both database and filesystem storage and I can provide it both with DB connection string and a local directory path on creation time. I think it should be a good practice, let me know if I'm wrong.
Now the problem: how I can know the local directory path from inside of the LocalFile or UserImage objects so they can implement LocalPath and Url properties? In other words, how some other part of the application can know what's the actual Path/Url of the LocalFile or UserImage instance? Or is there a way to provide these objects with LocalDir as they're being created inside DbContext? At last, what is the alternate way to incapsulate local storage operations within UserImage so any outed code never care how and where the file is stored?
You should create interface for your file operations that will have two methods: Stream GetFile(string fileName) and void PutFile(Stream fileStream, string fileName) and implement it with concrete class that will have constructor with parameter locationPath:
public interface IFileRepository
{
Stream GetFile(string fileName);
void PutFile(Stream fileStream, string fileName);
}
public class FileRepository
{
private readonly string localPath;
public FileRepository(string localPath)
{
_localPath = localPath;
}
public Stream GetFile(string fileName)
{
var file = //get filestram from harddrive using fileName and localPath
return file;
}
...
public void PutFile(Stream fileStream, string fileName)
{
//save input stream to disk file using fileName and localPath
}
}
In your DbContext class you should create private field of type IFileRepository and in constructor initialize it from parameter:
public class SomeDbContext:DbContext
{
private readonly IFileRepository _fileRepository;
public SomeDbContext(IFileRepository fileRepository)
{
_fileRepository = fileRepository;
}
...
}
And use this _fileRepository to put and get files in DbContext methods.
Concrete classes for interface type parameters should be passed by Inversion of Control container (or other implementations of Inversion of Control principle).
Update:
public class UserImage
{
public string Description { get; set; }
[NotMapped]
public LocalFile File { get; set; }
}
// not EF entity
public class LocalFile
{
private readonly string _filePath;
public LocalFile(string filePath)
{
_filePath=filePath;
}
public string Name { get; set; }
public string LocalPath { // aggregate Name and filePath }
public string Url { // should return LocalPath mapped to Url } If i where you, i would write helper for this
}
I think my mistake is that i'm trying to access context properties (i.e. directory path) from inside of the entity. EF database context architecture doesnt implement it and the entities don't have idea how they are stored. I wouldn't like to voilate this canon.
The directory for storing files can be considered either as context property (like connection string) and entity property (like path). To implement first case i can provide myDbContext with the Directory property and then resolve all paths via context instance by calling myContext.GetUrl(userImage.FileName). But myDbContext is not always directly accessible from presentation level and i'll be unable to extract userImage's Url to set it on web page until i propogate myDbContext to all upper layers.
If I consider Directory as LocalFile's property then i need somehow to inject its value, either in constructor:
public class LocalFile{
// Constructor
public LocalFile(string dir){ // set current dir }
private string _dir;
public GetUrl(){ // return _dir + filename }
}
// cons: parameterless constructor that will be called by DbContext on getting
// data from DB won't set `_dir` and GetUrl won't return correct result
or using static directory that is set up earlier (say in global.asax):
public class LocalFile{
// Constructor
public LocalFile(){ // empty }
public static Dir;
public GetUrl(){ // return Dir + filename }
}
or even directly accessing web.config to get paths:
public class LocalFile{
// Constructor
public LocalFileType(){ // empty }
public GetUrl(){ // read dir from web.config + filename }
}
// not good idea to access web-specific assemblies from EF data classes
or making extension methods at upper layers where web.config is accessible:
public static class MyExtensions
{
public static string GetUrl(LocalFile localFile)
{
// dir from web.config + localFile.Name
}
}
So, there are many possible solutions and each has its own disadvantages. My case is little bit more complicated as my dir path also depends on LocalFile's parent user's ID so i have dir template users/{0}/image.jpg in web.config instead of simple path.
What i've done to achieve my targets:
put url template of type users/{0}/{1} (0 - parent UserId, 1 -
fileName) to web.config
created class Settings nearby my EF entities
public static class Shared
{
public static Func<string, int, string> LocalFileUrlResolver;
}
populated its values on application start
protected void Application_Start()
{
Shared.LocalFileUrlResolver =
(fileName, userId) =>
String.Format(ConfigurationManager.AppSettings["LocalFileUrl"], userId, fileName);
}
made my User provide its own images with Url resolver at creation
time
public User()
{
// ...
Image = new LocalFile(
"userpic.css",
fileName => Shared.LocalFileUrlResolver(fileName, userId)
);
}
made my LocalFile constructor accept Func<string, string> param
that resolves full Url of given file name
public class LocalFile
{
public LocalFile(
string fileName,
Func<string, string> fnUrlResolver
)
{
FileName = fileName;
_fnUrlResolver = fnUrlResolver;
}
private readonly Func<string, string> _fnUrlResolver;
public string FileName { get; private set; }
public string Url { get { return _fnUrlResolver(FileName); } }
}
Yes, so many lines. I take dir template from web.config, inject it into static member of data access layer and make it more specific on User creation point for user's local images.
I am absolutely not sure does it worth the cost. Maybe in future i'll choose direct access to web.config :)

Categories