In my projects I have to interact with an ERP system that exposes about 30 different API DLLs.
The ERP company systematically creates new versions of their system and I'm forced to change the DLLs to the new versions. However, not all of my clients update the ERP, so I'm also forced to maintain old references. My current solution to this problem is:
1) For every ERP version I create an 'ApiWrapper' project, referencing the DLLs for this ERP version.
2) In my main project I reference those 'ApiWrappers' and use a selected one of those.
An example function inside of the 'ApiWrapper' looks like this:
public void AddContractorAttribute(Ustawienia settings, string attributeCode, string attributeValue, int contractorId)
{
CreateNewSession();
CDNHeal.Kontrahenci AllContractors = (CDNHeal.Kontrahenci)session.CreateObject("CDN.Kontrahenci", null);
CDNHeal.IKontrahent SelectedContractor = (CDNHeal.IKontrahent)AllContractors[$"Knt_KntId = {contractorId}"];
CDNBase.ICollection AllAttributes = (CDNBase.ICollection)(session.CreateObject("CDN.DefAtrybuty", null));
CDNTwrb1.IDefAtrybut SelectedAttribute = (CDNTwrb1.IDefAtrybut)AllAttributes[$"dea_Kod = '{attributeCode}'"];
CDNTwrb1.IKntAtrybut NewAttributeValue = (CDNTwrb1.IKntAtrybut)SelectedContractor.Atrybuty.AddNew(null);
NewAttributeValue.DefAtrybut = (CDNTwrb1.DefAtrybut)SelectedAttribute;
NewAttributeValue.Wartosc = attributeValue;
session.Save();
}
Now, the problem I have is: if I want to add or change a function in the ApiWrapper, I have to do it in every single one of those. They don't differ code-wise, they only reference a different set of DLLs. Is there a way to solve this issue through class inheritance or otherwise?
You can design a class that will be implemented with the builder pattern or factory method (use some creational pattern, please read about these patterns it will help you reduce your codebase). The approach is to design one generic class which will be used everywhere. So, you can modify it easily. You need to figure out how to distinguish your dlls. Dll's References could be distinguished in two ways:
by the full name of the assembly (usually it includes the version
of assembly).
or you can load all dlls into memory and
reflectively read dll's version.
After distinguishing versions you can easily put all dlls together and ship it.
So, basically you should design a generic builder, which will take a version number as a parameter and return a well-prepared bench of dlls.
Hope it helps.
Related
We have a system that manages generic physical resources. There are over 500 individual resources. The system is used for many different things and to make the software easier to write we use aliases.
For example, a physical resource TG67I9 is given an alias of "RightDoor". When code is written RightDoor is used instead of TG67I9 making the code more readable. This alias list is loaded as a text file with references to resources and their aliases. This system uses literally hundreds of different alias lists to reference the same physical resources.
This type of setup has two major shortcomings. First, when resources are called using their aliases, they are passed in as strings. Door.Open("RightDoor") for example. This does not give any tooltips or smart anything making the code more difficult to write. It basically requires constantly referencing the alias list. Is it RightDoor or Right_Door or right-door or... you get the idea. The second is that there is no validation of parameters until execution. All the compiler knows is that a string is passed in and then it's happy. Only when the code is run, the function tries to access the resource through its alias and fails because it can't find right-door because it's supposed to be RightDoor. An error is displayed. This requires tedious debugging and running the code over and over to weed out any bad aliases.
Is there a better way to do this? Such that an alias list can be made with a cross-reference of physical resources to their alias names and after the list is made that tooltips could appear suggesting resources. (Assume that a new system could be written from scratch)
I'm using the latest .NET with VisualStudio 2017 and C# to write the code.
The simplest approach is most likely a "string enum":
public class Resources {
public const string
LeftDoor = "TG67I8",
RightDoor = "TG67I9";
}
Sample use:
Door.Open(Resources.RightDoor);
Hovering over .RightDoor in VS shows a tooltip (constant) string Resources.RightDoor = "TG67I9"
Right-clicking .RightDoor and selecting Find All References will show where the variable is used.
Another option can be adding the strings in the Resources section of the Project Properties, and then:
using YourProjectNameSpace.Properties;
...
Door.Open(Resources.RightDoor);
That is a bit slower, because the resource(s) are retrieved at run-time, but allows to load the resources from a custom external file separate from the executable.
Use a static class with constants. I have done the same many times and still do. Plus .NET does this as well.
public static class PhysicalResources
{
public const string One = "Uno";
public const string Two = "Deux";
// ...
}
In the application I'm developing, the same software package serves many industries, and those industries have different vocabulary for what is essentially the same thing. The application is a C# server, to which a WPF desktop app makes socket-based XML requests.
For example, some customers may call something an "Item", some call it a "Part", or some call it a "SKU".
The goal is for the application to be able to relabel itself based on a "Vocabulary" setting that we create for the user. Typically, a given customer's vocabulary will only differ by perhaps 5-25 words/phrases out of the entire application. These custom vocabularies are specific to/created by the customer, and wouldn't be kept with the main application distribution.
My initial thought was to do this with custom CultureInfo, (e.g. "en-AC" for "Acme" company), supply just values that differ from the base en-US in that resource file.
The en-AC.resx resource could be kept on the server, loaded by the server, and also transmitted for loading into the WPF client app.
Problem with that thus far seems to be that the ResourceManager does not correctly pick strings for custom cultures, a'la this thread, and I've not been able to solve that yet. As well, as the app is ClickOnce deployed, we may not have permission to register a new culture.
My next thought, since the number of phrases to modify is so small, was to replace the resource value at runtime, but that seems to be a bit of a no-no as well, searching around.
So, thought I would ask the community for their suggestions on how to handle this.
Open to suggestions and ideas...
Because it's only about a few words I think I'd do it via a naming convention. Suppose you defined the string key "MyCompany". You usually access this way:
string myString1 = Properties.Resource.MyCompany;
But it is also ok to Access it that way:
string myString2 = Properties.Resource.ResourceManager.GetString ("MyCompany")
It's exactly the same (but dealing with strings as identifiers - which is somewhat error prone). What you now can do is to check for a special name first that you syntesize like "MyCompany_AC". The drawback is you need your own wrapper for each string:
string MyCompany
{
get
{
string myString = Properties.Resource.ResourceManager.GetString ("MyCompany_" + theCompanyPostfix);
if (myString == null)
{
myString = Properties.Resource.ResourceManager.GetString ("MyCompany");
}
return myString;
}
}
I am wondering why there is no .ToShortDateString in the .NET Portable Class Library. I have 2 projects (Silverlight, and regular .NET Class Library) that use the same code, and the code involves calling .ToShortDateString() on a DateTime object. In order to reuse the same code instead of copying it in 2 places, I created a portable class library so it can be imported by both Silverlight and .NET Class Library. Unfortunately, it doesn't seem like .ToShortDateString() is available when using the class library. I can accept a string parameter in the portable class library method and pass the .ToShortDateString() value from both silverlight and class library projects, but I am wondering why this method isn't native for the portable library. Is it a culture issue?
It was removed to deemphasize its use from what we consider the "modern" surface area, which I hint about here (What is .NET Portable Subset (Legacy)?). This means that it does not show up newer platforms (such as Windows Store apps) and does not show up in portable libraries.
You can mimic its behavior by simply passing "d" to DateTime.ToString().
We wanted to deemphasize its use because it is the only .NET Framework date format that does not have a representation at the Windows OS level. This causes it to not reflect/respect the formatting changes made by the user. In certain organizations and governments, it is important that these settings are respected.
While most of methods/properties that belong to types defined in System namespace are available in PCLs, there are some exceptions, and ToShortDateString is one of them. Below is the list of portable DateTime members. I don't know what was the reason behind the exclusion of some string conversion methods, but I guess this is due to redundancy. As cadrell0 pointed out, you can always achieve the same by using ToString with a parameter.
T:System.DateTime
M:System.DateTime.ToString(System.String)
M:System.DateTime.op_GreaterThan(System.DateTime,System.DateTime)
M:System.DateTime.ParseExact(System.String,System.String[],System.IFormatProvider,System.Globalization.DateTimeStyles)
M:System.DateTime.get_Month
M:System.DateTime.FromFileTimeUtc(System.Int64)
M:System.DateTime.get_Date
M:System.DateTime.get_TimeOfDay
M:System.DateTime.get_Kind
M:System.DateTime.ToUniversalTime
M:System.DateTime.get_Year
M:System.DateTime.op_Subtraction(System.DateTime,System.TimeSpan)
M:System.DateTime.get_Second
M:System.DateTime.get_DayOfWeek
M:System.DateTime.TryParse(System.String,System.IFormatProvider,System.Globalization.DateTimeStyles,System.DateTime#)
M:System.DateTime.#ctor(System.Int32,System.Int32,System.Int32,System.Int32,System.Int32,System.Int32,System.Int32)
M:System.DateTime.get_Day
P:System.DateTime.Date
M:System.DateTime.op_Addition(System.DateTime,System.TimeSpan)
M:System.DateTime.IsDaylightSavingTime
M:System.DateTime.get_DayOfYear
M:System.DateTime.ToFileTime
M:System.DateTime.Subtract(System.DateTime)
M:System.DateTime.IsLeapYear(System.Int32)
M:System.DateTime.#ctor(System.Int32,System.Int32,System.Int32,System.Int32,System.Int32,System.Int32,System.Int32,System.DateTimeKind)
M:System.DateTime.ParseExact(System.String,System.String,System.IFormatProvider,System.Globalization.DateTimeStyles)
P:System.DateTime.Day
M:System.DateTime.get_Hour
M:System.DateTime.Equals(System.DateTime)
M:System.DateTime.get_UtcNow
M:System.DateTime.get_Today
M:System.DateTime.TryParse(System.String,System.DateTime#)
P:System.DateTime.Kind
M:System.DateTime.System#IComparable#CompareTo(System.Object)
P:System.DateTime.UtcNow
P:System.DateTime.Hour
P:System.DateTime.Millisecond
M:System.DateTime.Parse(System.String)
F:System.DateTime.MinValue
M:System.DateTime.op_GreaterThanOrEqual(System.DateTime,System.DateTime)
M:System.DateTime.#ctor(System.Int64,System.DateTimeKind)
M:System.DateTime.GetHashCode
P:System.DateTime.Year
M:System.DateTime.Add(System.TimeSpan)
M:System.DateTime.Equals(System.DateTime,System.DateTime)
M:System.DateTime.ToString(System.IFormatProvider)
M:System.DateTime.get_Now
P:System.DateTime.Month
M:System.DateTime.DaysInMonth(System.Int32,System.Int32)
M:System.DateTime.AddMinutes(System.Double)
M:System.DateTime.get_Minute
M:System.DateTime.#ctor(System.Int64)
M:System.DateTime.op_LessThanOrEqual(System.DateTime,System.DateTime)
M:System.DateTime.ToString(System.String,System.IFormatProvider)
P:System.DateTime.DayOfYear
M:System.DateTime.AddMilliseconds(System.Double)
P:System.DateTime.Second
P:System.DateTime.DayOfWeek
M:System.DateTime.op_Equality(System.DateTime,System.DateTime)
M:System.DateTime.#ctor(System.Int32,System.Int32,System.Int32,System.Int32,System.Int32,System.Int32)
M:System.DateTime.TryParseExact(System.String,System.String,System.IFormatProvider,System.Globalization.DateTimeStyles,System.DateTime#)
M:System.DateTime.ToFileTimeUtc
P:System.DateTime.Today
M:System.DateTime.op_LessThan(System.DateTime,System.DateTime)
M:System.DateTime.get_Millisecond
M:System.DateTime.op_Subtraction(System.DateTime,System.DateTime)
M:System.DateTime.#ctor(System.Int32,System.Int32,System.Int32)
M:System.DateTime.ParseExact(System.String,System.String,System.IFormatProvider)
M:System.DateTime.AddSeconds(System.Double)
M:System.DateTime.AddMonths(System.Int32)
M:System.DateTime.AddYears(System.Int32)
M:System.DateTime.Parse(System.String,System.IFormatProvider,System.Globalization.DateTimeStyles)
M:System.DateTime.get_Ticks
P:System.DateTime.Ticks
M:System.DateTime.TryParseExact(System.String,System.String[],System.IFormatProvider,System.Globalization.DateTimeStyles,System.DateTime#)
M:System.DateTime.ToLocalTime
M:System.DateTime.op_Inequality(System.DateTime,System.DateTime)
M:System.DateTime.SpecifyKind(System.DateTime,System.DateTimeKind)
M:System.DateTime.AddHours(System.Double)
P:System.DateTime.Minute
M:System.DateTime.Subtract(System.TimeSpan)
M:System.DateTime.#ctor(System.Int32,System.Int32,System.Int32,System.Int32,System.Int32,System.Int32,System.DateTimeKind)
F:System.DateTime.MaxValue
M:System.DateTime.ToString
M:System.DateTime.FromFileTime(System.Int64)
P:System.DateTime.TimeOfDay
M:System.DateTime.Compare(System.DateTime,System.DateTime)
M:System.DateTime.CompareTo(System.DateTime)
M:System.DateTime.Parse(System.String,System.IFormatProvider)
M:System.DateTime.AddDays(System.Double)
P:System.DateTime.Now
M:System.DateTime.Equals(System.Object)
M:System.DateTime.AddTicks(System.Int64)
I'm using libgit2sharp and I'd like to get a Commit object representing something like HEAD~10. I tried repo.Lookup("HEAD~10"), but that doesn't work:
LibGit2Sharp.LibGit2Exception: An error was raised by libgit2. Class = GITERR_REFERENCE (-1).
The given reference name is not valid
at LibGit2Sharp.Core.Ensure.Success(Int32 result, Boolean allowPositiveResult)
at LibGit2Sharp.ReferenceCollection.Resolve[T](String name)
at LibGit2Sharp.Repository.Lookup(String shaOrReferenceName, GitObjectType type, LookUpOptions lookUpOptions)
at LibGit2Sharp.Repository.Lookup(String shaOrReferenceName, GitObjectType type)
at libgit_tmp.Program.Main(String[] args)
I realize I could do the same by something like the following code, but I'd still prefer it if I could specify the reference this way. Is there some way to do it? If not, is it a limitation of libgit2sharp or of libgit2?
var commit = repo.Head.Tip;
for (int i = 0; i < 10; i++)
commit = commit.Parents.First();
Unfortunately, LibGit2Sharp isn't able to accept parameters following the rev-parse revision-specification syntax.
The proposed workaround is currently the best possible implementation. It's fully compliant with the documentation which states
A suffix ~<n> to a revision parameter means the commit object that is the <n>th generation ancestor of the named commit object, following only the first parents.
However, a feature has been recently merged in the development branch of libgit2 which may cover "retrieving parent references" need and beyond.
A nice API is now available and makes possible to retrieve a concrete git object from a revparse textual specification. In order to get a quick peek at its usage, the tests are available here.
Binding this API and making it widely available to LibGit2Sharp is yet to be done.
I have a basic question.
1-
I want to use Science.dll provided at
http://www.sciencecode.com/
I want to add some new functions in some XXX.cs files and also some new YYY.cs files. Then I want to make dll of them again (Science.dll with changes) and use it. How it can be done.
Should I make a new project and add all more than 100 files (already given on website) in that project and some my new YYY.cs files and then what should be next step???
2-
I wanna ask about best way to put many different functions in one 'utilities.cs' file. Say I have different static functions *printmatrix, read_text_file,* etc. What should I do, so that I directly use them in main program. What should be the way in c#.In c++ I wrote header file and cpp file named utilities and then I used these functions.
Any good idea.
You cannot modify an existing assembly unless you have the source code of it. What you could do is create a new class library project in Visual Studio, add Science.dll as a reference and then add your own functions which could use functions in the referenced assembly. When you compile your project it will produce another assembly.
First you make a new project taht has reference on the science.dll.in Visual studio
You can inheritance its class and add yours functionality.
You can use partial class that has the same name as in the science.dll. and add your functionality
eg:
science.dll
public class Calc
{
public Int32 Add(Int32 a, Int32 b){..implementation...}
}
yourproject.dll
public partial class Calc
{
public Int32 Minus(Int32 a, Int32 b) {..implementation..}
}
You can use extension method with your functionality. This is depend on your implementation.
For detail implementation you can see on MSDN : http://msdn.microsoft.com/library for both C# and VB.NET on both syntak
In the caller project, make sure add reference both science.dll and yourproject.dll.