Class behavior based on given data - c#

I am receiving an IFormFile from a controller.
What I want to do next is to process it and get its content. I expect to get .docx, .txt or .pdf file and I want a single class to process any of these files based on extension given. I created and made my class to do it like that:
{
public static class DocumentProcessor // Should it be like this?
{
public static string GetContent(IFormFile file)
{
var result = new StringBuilder();
switch (Path.GetExtension(file.FileName))
{
case ".txt":
{
using(var reader = new StreamReader(file.OpenReadStream()))
{
while (reader.Peek() >= 0)
result.AppendLine(reader.ReadLine());
}
break;
}
}
return result.ToString();
}
}
}
Anyway, I feel like it is an extremely bad solution just because it is static. I could use the strategy pattern, but how do I define what strategy context has to use?
Should I create another class that
returns a Strategy object depending on IFormFile object extension. But I feel it is also a bad solution
I would like to know what is the best way to solve this problem

Create a new interface
interface IDocumentParser {
string GetContent(IFormFile file);
}
Implement that interface once per parser extension, e.g.:
class TextFileParser : IDocumentParser {
public string GetContent(IFormFile file) {
//your implementation code here
}
}
Then implement a factory:
class ParserFactory {
public static IDocumentParser GetParserForFilename(string filename) {
/*
This is the simple way. A more complex yet elegant way would be for all parsers to include a property exposing the filetypes it supports, and they are loaded through reflection or dependency injection.
*/
switch (Path.GetExtension(fileName))
{
case ".txt":
{
return new TextFileParser();
}
// add additional parsers here
}
return null;
}
}
And use:
IDocumentParser parser = ParserFactory.GetParserForFilename(file.FileName);
string content = parser.GetContent(file);
This is known as "Inversion of Control".

Related

Accessing value of subclass property without instance

I am currently trying to save and load data for multiple classes to/from disk. I am using JSON serialization to read and write a text file with a custom file extension. This works perfectly fine.
However, instead of duplicating the code in every class I want to use inheritance and only have the save/load code once in an abstract superclass. I want to have a different file extension for each class.
Saving is not a problem, because I have an object, so I can simply use an abstract property, but when I want to load the data I don't, so I can't get the property value without first creating an instance of the type I want to load, which I find stupid.
Also, I can't make abstract static/const properties/fields in C# (for stupid reasons, don't even start), and I am out of good ideas.
//this is fine, although I don't really need the new constraint, but I keep it for consistency with the Load function
public static void Save<T>(string filename, T obj) where T : JsonSerializeable, new() {
if (filename.IsNullOrWhiteSpace()) filename = $"{DEFAULT_FILENAME}";
string path = Path.ChangeExtension($"{DIRECTORY_NAME}/{filename}", obj.fileExtension);
path = Path.ChangeExtension(path, obj.fileExtension);
if (!Directory.Exists(DIRECTORY_NAME)) Directory.CreateDirectory(DIRECTORY_NAME);
File.WriteAllText(path, JsonConvert.SerializeObject(obj, Formatting.None));
}
//this works, but I hate that I need to create an instance that has no other use than getting the property value
public static bool Load<T>(string filename, out T obj) where T : JsonSerializeable, new() {
if (filename.IsNullOrWhiteSpace() || !Directory.Exists(DIRECTORY_NAME)) {
obj = default;
return false;
}
string fileExtension = new T().fileExtension; //TODO -.-
string path = Path.ChangeExtension($"{DIRECTORY_NAME}/{filename}", fileExtension);
if (!File.Exists(path)) {
obj = default;
return false;
}
obj = JsonConvert.DeserializeObject<T>(File.ReadAllText(path));
return true;
}
Alternatively, I could have public save/load methods in the subclasses, with the desired interface (i.e. without the extension) and have the superclass methods protected and there pass the extension as parameter. However, I still don't really like that. It is acceptable, and my current implementation (because creating a useless object doesn't fly), but is there a good way to do it with only the superclass functions? (and no, I don't want to use the class name as the file extension)
Note: As of now this is more of an academic question, since I have a working implementation, but this was only the latest instance of that same problem popping up in my programming over and over again, and I always find some kind of workaround. I would love to finally have a good solution.
One way to do this would be to create an abstract class with a static member for the Extension property, and then hide that property in the child class implementations:
public abstract class FileType
{
public static string Extension { get; } = "default";
}
public class PDFFile : FileType
{
public static new string Extension { get; } = "pdf";
}
public class TextFile : FileType
{
public static new string Extension { get; } = "txt";
}

How to assign values of different types to a variable inside if statements and then use this variable after the if statements?

I am retrieving different types of documents from database, and assigning the received data to the variable items. Different methods are used to retrieve different document types, hence the need for if statements. I cannot initialize items before the if statements, because I don't know beforehand what type of document the user is retrieving. The problem is that I therefore cannot use items after the relevant īf statement has been executed. How to solve this issue? A simplified method:
public ActionResult ExportToExcel()
{
...
if (request.docType == "docType1")
{
var items = _provider.GetDocumentsOfType1(request);
}
else if (request.docType == "docType2")
{
var items = _provider.GetDocumentsOfType2(request);
}
else if ...
}
After retrieving the data, I would need to do some formatting based on what data is in the items variable, and of course return the data. It seems that the only viable thing is to replace the if statements with separate methods, and call the formatting etc. methods from there. But can it all be done within a single method?
To avoid multiple if statements, you can use the SOLID design principle.
So, you can do this:
interface IExcelDoc
{
ActionResult ExportToExcel();
}
public class ExcelDoc1 : IExcelDoc
{
public ActionResult ExportToExcel()
{
// implementation here
}
}
public class ExcelDoc2 : IExcelDoc
{
public ActionResult ExportToExcel()
{
// implementation here
}
}
Then your driver class can be like:
public class Test
{
public void Main()
{
IExcelDoc excelDoc = GetDocType();
excelDoc.ExportToExcel();
}
private IExcelDoc GetDocType()
{
if(...)
return new ExcelDoc1();
else
return new ExcelDoc2();
}
}
This will make your code maintainable in future.
You can use dynamic pseudo-type.
Or, you can declare variable as object.
The both of these solutions have drawbacks.
The best solution would be using an interface, which is provided by every possible types of documents.
See if you can use an interface that is shared between the various document types, or else create such an interface:
public interface IDocument { }
public class Doc1 : IDocument { }
public class Doc2 : IDocument { }
If the various DocX classes have shared properties or operations that you need to use, then by all means add those into the IDocument interface, that will make them callable without any need for type checking and type casting.
You can then declare items as IEnumerable<IDocument>, and have the GetDocumentsOfTypeX()-methods all return a value of that type:
IEnumerable<IDocument> items;
items = GetDocumentsOfType1();
public static IEnumerable<IDocument> GetDocumentsOfType1()
{
return new List<Doc1>() { new Doc1() };
}
// (etc)
Working demo: https://dotnetfiddle.net/Dwmmdf

Create family of objects depends on a string or enum violates Open - Closed principle

I am developing a library to convert HTML document as word document. This is done by traversing through the HTML document and process the HTML elements one by one. There are family of classes to process each HTML tag.
public abstract class DocxElement
{
public void Process();
}
public class DocxTable : DocxElement
{
public override void Process(){}
}
public class DocxDiv : DocxElement
{
public override void Process(){}
}
The above classes are responsible to process its html counterpart. So whenever I expand the library to support an additional html tag, I will just create a sub class from DocxElement. The html parser uses a factory class to generate concerate DocxElement class whenever it meets an HTML tag.
public class ElementFactory
{
public DocxElement Resolve(string htmlTag)
{
switch(htmlTag)
{
case "table":
return new DocxTable();
case "div":
return new DocxDiv();
}
}
}
Now I feel it violates the Open closed principle. I prefer not to use reflection just because of design patterns require that. So I created a singleton dictionary to register the element classes.
Dictionary<string, Func<DocxElement>> doc;
doc.Add("table",()=>{ new DocxTable();});
Finally I was able to eliminate the switch statement. Still I need to add elements to the dictionary when I create a new sub class.
Is there any better method to do this? Please advice.
I would say your Dictionary method is fine. Anything else trying to make this generic will lose the static compile time checking. If you're ready to sacrifice the compile time checking, you can use reflection to make this code generic.
public class ElementFactory
{
public DocxElement Resolve(string htmlTag)
{
var type = Type.GetType(string.Format("{0}.Docx{1}",
typeof(ElementFactory).Namespace,
CultureInfo.CurrentCulture.TextInfo.ToTitleCase(htmlTag)));
return (DocxElement)Activator.CreateInstance(type);
}
}
How to use:
ElementFactory factory = new ElementFactory();
var table = factory.Resolve("table");//Works
var div = factory.Resolve("div");//Works
var span = factory.Resolve("span");//Explodes!!
As you can see this can fail a runtime for several reasons. Type not found, Type found but no public parameterless constructor, Type found but it doesn't derive from DocxElement, etc etc..
So it is better you can stick with Dictionary option IMO.

Following the DRY principle in ASP.NET

I have just recently got involved in a classic ASP.NET project which contains lots of storing and reading values from the session and query strings. This could look something like the following:
Session["someKey"]=someValue;
And somewhere else in the code the value in the session is read. Clearly this violates the DRY principle since you'll have the literal string key spread out all over the code. One way to avoid this could be to store all keys as constants that could be referenced everywhere there is a need to read and write to the session. But I'm not sure that's the best way to do it. How would you recommend I best handle this so that I don't violate the DRY principle?
Create a separate public class where you can define your constants, e.g
public class SessionVars
{
public const string SOME_KEY = "someKey";
public const string SOME_OTHER_KEY = "someOtherKey";
}
and then anywhere in your code you can access session variables like this:
Session[SessionVars.SOME_KEY]=someValue;
This way you can get IntelliSence and other bells and whistles.
I think you're reading too much into DRY. I pertains more to things that could be wrapped up in a function. I.e. instead of repeating the same fives lines all over the place wrap those 5 lines in a function and call the function everywhere you need it.
What you have as an example is just setting a value in a dictionary (the session object in this case), and that is the simplest way to store and retrieve objects in it.
I can't remember for the life of me where I humbly re-purposed this code from, but it's pretty nice:
using System;
using System.Web;
namespace Project.Web.UI.Domain
{
public abstract class SessionBase<T> where T : class, new()
{
private static readonly Object _padlock = new Object();
private static string Key
{
get { return typeof(SessionBase<T>).FullName; }
}
public static T Current
{
get
{
var instance = HttpContext.Current.Session[Key] as T;
lock (SessionBase<T>._padlock)
{
if (instance == null)
{
HttpContext.Current.Session[Key]
= instance
= new T();
}
}
return instance;
}
}
public static void Clear()
{
var instance = HttpContext.Current.Session[Key] as T;
if (instance != null)
{
lock (SessionBase<T>._padlock)
{
HttpContext.Current.Session[Key] = null;
}
}
}
}
}
The idea behind it two fold. The type created should be the only type you need. It's basically a big strongly-typed wrapper. So you have some object you want to keep extending information in:
public class MyClass
{
public MyClass()
public string Blah1 { get; set; }
}
Then down the road you extend MyClass and you don't want to have to remember all the Key Values, store them in AppSettings or Const variables in Static Classes. You simply define what you want to store:
public class MyClassSession : SessionBase<MyClass>
{
}
And anywhere in your program you simply use the class.
// Any Asp.Net method (webforms or mvc)
public void SetValueMethod()
{
MyClassSesssion.Current.Blah1 = "asdf";
}
public string GetValueMethod()
{
return MyClassSession.Current.Blah1;
}
Optionally you could place the access to this session object in a base page and wrap it in a property:
class BasePage : Page
{
...
public string MySessionObject
{
get
{
if(Session["myKey"] == null)
return string.Empty;
return Session["myKey"].ToString();
}
set
{
Session["myKey"] = value;
}
}
...
}
Here you are repeating the myKey string but it is encapsulated into the property. If you want to go to the extreme of avoiding this, create a constant with the key and replace the string.

How can I override get and set methods for all properties in a class?

I have got several classes looking like the one below, and I need to do some checks in the get method and custom set methods. Adding the code in each get and set method makes everything look really messed up.
Is there a way I can override the get and set methods for all properties in an entire class?
public class Test
{
private DataRow _dr;
public Test()
{
_dr = GetData();
}
public string Name
{
get { return _dr[MethodBase.GetCurrentMethod().Name.Substring(4)].ToString(); }
set
{
VerifyAccess(MethodBase.GetCurrentMethod().Name.Substring(4), this.GetType().Name);
_dr[MethodBase.GetCurrentMethod().Name.Substring(4)] = value;
}
}
public string Description
{
get { return _dr[MethodBase.GetCurrentMethod().Name.Substring(4)].ToString(); }
set
{
VerifyAccess(MethodBase.GetCurrentMethod().Name.Substring(4), this.GetType().Name);
_dr[MethodBase.GetCurrentMethod().Name.Substring(4)] = value;
}
}
public string DescriptionUrl
{
get { return _dr[MethodBase.GetCurrentMethod().Name.Substring(4)].ToString(); }
set
{
VerifyAccess(MethodBase.GetCurrentMethod().Name.Substring(4), this.GetType().Name);
_dr[MethodBase.GetCurrentMethod().Name.Substring(4)]= value;
}
}
private void VerifyAccess(string propertyname, string classname)
{
//some code to verify that the current user has access to update the property
//Throw exception
}
private DataRow GetData()
{
//Some code to pull the data from the database
}
}
I think what you need is a Proxy on your class, read about Proxy Pattern and Dynamic Proxies
Not directly, there isn't a way to do it with just a compiler. You'd have to generate your entire binary file, then post-process it with some external tool.
This post describes a somewhat similar issue; I hope it helps.
There's a variety of ways to do it.
One would be to create a proxy class (mentioned before), but that would require a lot of refactoring on your behalf.
Another way is with aspects. These do exactly what you're after (insert code based on a pre-requisite.. i.e. all get methods in a class that inherit from x). I ran into a similar problem (actually the exact same problem - checking for security on method calls), and couldn't find cheap/free aspect software that fulfilled my needs.
So, I decided to use Mono-Cecil to inject code before function calls.
If you're interested (it gets a bit messy dealing with IL codes) I can post an old copy of the source
You should extract common code to separate get/set methods, after that you'll be able to add common logic to your properties. By the way, I would do such extraction anyway to avoid copy/paste in the code.
Smth like this:
public string Name
{
get { return GetProperty(MethodBase.GetCurrentMethod()); }
set
{
SetProperty(MethodBase.GetCurrentMethod(), value);
}
}
private string GetProperty(MethodBase method)
{
return _dr[method.Name.Substring(4)].ToString();
}
private void SetProperty(MethodBase method, string value)
{
string methodName = method.Name.Substring(4);
VerifyAccess(methodName , this.GetType().Name);
_dr[methodName] = value;
}
This can be done with indirect value access, e.g. obj.PropA.Value = obj.PropB.Value + 1 -- you can even keep strong typing information. It can be implemented with either attributes or direct-instantiation.
// attribute -- bind later in central spot with annotation application
[MyCustomProp(4)] CustProp<int> Age;
// direct -- explicit binding, could also post-process dynamically
CustProp<int> Age = new CustProp<int>(4, this);
Alternatively, perhaps using a template system such as TT4 may be a viable approach.
However, don't forget "KISS" :-)
I would love for someone to give a better answer for this.
I'm looking for an answer now… best idea I have had would be to define all the properties you want to have be validated as a generic class. For example:
public class Foo {
public String Name {
get{ return _Name.value; }
set{ _Name.value = value; }
}
private Proxy<String> _Name;
static void main(String[] args) {
Foo f = new Foo();
//will go through the logic in Proxy.
f.Name = "test";
String s = f.Name;
}
}
public class Proxy<T> {
public T value {
get {
//logic here
return _this;
} set {
//logic here
_this = value;
}
}
private T _this;
}

Categories

Resources