Do repeated calls to AddHttpClient overwrite each other? - c#

I have one NuGet package that has code like this in it:
services.AddHttpClient("CompanyStandardClient").AddCompanyAuthenticationHeaders();
And another Nuget project with code like this in it:
services.AddHttpClient("CompanyStandardClient").AddCompanyHeaderPropagation();
Basically, one NuGet sets up my company's authentication, and another sets up the company's header propagation.
I usually would do this code like this:
services.AddHttpClient("CompanyStandardClient").AddCompanyAuthenticationHeaders().AddCompanyHeaderPropagation()
I am worried that if I do them separate, only one will be in effect. I looked at the code on GitHub and it returns a newed DefaultHttpClientBuilder for each call.
return new DefaultHttpClientBuilder(services, name);
But I am not sure if this means that the previous entry was overwritten.
Can the same named client be "added" separately? Or will it overwrite?

I think it can be done for the same named client based on the internal comments here.
// See comments on HttpClientMappingRegistry.
private static void ReserveClient(IHttpClientBuilder builder, Type type, string name, bool validateSingleType)
{
var registry = (HttpClientMappingRegistry)builder.Services.Single(sd => sd.ServiceType == typeof(HttpClientMappingRegistry)).ImplementationInstance;
Debug.Assert(registry != null);
// Check for same name registered to two types. This won't work because we rely on named options for the configuration.
if (registry.NamedClientRegistrations.TryGetValue(name, out Type otherType) &&
// Allow using the same name with multiple types in some cases (see callers).
validateSingleType &&
// Allow registering the same name twice to the same type.
type != otherType)
{
string message =
$"The HttpClient factory already has a registered client with the name '{name}', bound to the type '{otherType.FullName}'. " +
$"Client names are computed based on the type name without considering the namespace ('{otherType.Name}'). " +
$"Use an overload of AddHttpClient that accepts a string and provide a unique name to resolve the conflict.";
throw new InvalidOperationException(message);
}
if (validateSingleType)
{
registry.NamedClientRegistrations[name] = type;
}
}
Source
The client options configurations will aggregate to a single option.

Related

MongoDB Serialization C# - Adding Additional Encrypted Field Properties

I am trying to write a MongoDb serializer in c# that will allow me to decorate properties via a [Encrypt()] attribute and then at runtime it would allow me to generate an additional property called PropertyName_Encrypted which would contain the encrypted value.
On deserialization, the encrypted property value would be set in the parent property so that the default GET for the property always returns the encrypted value. Users will then call an optional Decrypt() method on the object to get decrypted values.
In doing so, I'm running into some interesting challenges:
How do I add Additional properties to the document when I am serializing current Element? How do I get the current element's name?
Is there a way I can read a specific property from the document/object? For e.g. say I want to pass a symmetric encryption key and read that to encrypt the data while serializing the current element? Is there any way I can do that?
Here are things I have done so far:
I've built an Encrypt Attribute as follows:
[AttributeUsage(AttributeTargets.Property)]
public class EncryptAttribute : Attribute
{
private readonly EncryptedFieldType _fieldType;
private readonly bool _tokenizeDisplay;
private readonly string _encryptedFieldName;
/// <summary>
///
/// </summary>
/// <param name="fieldType">The field type to encrypt. Useful if display needs to show some formatting. If no formatting is necessary, simply set to "Other".</param>
/// <param name="tokenizeDisplay">If set to true, will persist the tokenized value in the original field for display purposes.</param>
/// <param name="encryptedFieldName">Optional. If set, will save the encrypted value in the field name specified. By default all encrypted field values are stored in the corresponding _Encrypted field name. So EmailAddress field if encrypted, would have value under EmailAddress_Encrypted.</param>
public EncryptAttribute(EncryptedFieldType fieldType, bool tokenizeDisplay, string encryptedFieldName = "")
{
_fieldType = fieldType;
_tokenizeDisplay = tokenizeDisplay;
_encryptedFieldName = encryptedFieldName;
}
}
I read this Attribute on Startup and add an Encryption Serializer to the properties that are decorated using this attribute. The code that does that is like so:
var assemblies = AppDomain.CurrentDomain.GetAssemblies()
.Where(x => x.FullName.StartsWith("MongoCustomSerializer"))
.ToList();
var mapper = new Mapper();
foreach (var assembly in assemblies)
{
mapper.Map(assembly);
}
The mapper simply checks which properties in the document have the Encrypt attribute to add the serializer:
public sealed class Mapper
{
public void Map(Assembly assembly)
{
var encryptableTypes = assembly.GetTypes().Where(p =>
typeof(IEncryptable).IsAssignableFrom(p) && p.IsClass && !p.IsInterface && !p.IsValueType &&
!p.IsAbstract).ToList();
if (encryptableTypes.Any())
{
foreach (var encryptableType in encryptableTypes)
{
Map(encryptableType);
}
}
}
private void Map(Type documentType)
{
var properties =
documentType.GetProperties(BindingFlags.Public | BindingFlags.Instance);
if (properties.Length <= 0)
{
return;
}
foreach (var property in properties)
{
RegisterEncrpytionSerializer(property, typeof(EncryptAttribute), documentType);
}
}
private void RegisterEncrpytionSerializer(PropertyInfo property, Type encryptAttributeType, Type documentType)
{
var encryptAttributes = property.GetCustomAttributes(encryptAttributeType, false).ToList();
if (!encryptAttributes.Any()) return;
var memberMap = BsonClassMap.LookupClassMap(documentType).GetMemberMap(property.Name);
memberMap?.SetSerializer(new EncryptionSerializer());
}
}
In my unit tests, I'm getting an error stating that the Bson Class Map is already frozen. Even if I were to figure out a way to bypass that, how would this EncryptionSerializer class work to where I could write an additional property?
Would love to see if someone can assist!
UPDATE 1 - I was able to get the FREEZE error taken care of. It would appear that the LookupClassMap freezes the Member and Class Map info.
This change from the link allows me to take care of that issue:
private void RegisterEncrpytionSerializer(PropertyInfo property, Type encryptAttributeType, Type documentType)
{
var encryptAttributes = property.GetCustomAttributes(encryptAttributeType, false).ToList();
if (!encryptAttributes.Any()) return;
var classMapDefinition = typeof(BsonClassMap<>);
var classMapType = classMapDefinition.MakeGenericType(documentType);
var classMap = (BsonClassMap)Activator.CreateInstance(classMapType);
classMap.AutoMap();
var memberMap = classMap.GetMemberMap(property.Name);
memberMap?.SetSerializer(new KeyVaultEncryptionSerializer(memberMap.ElementName));
}
Are you using a service for saving/retrieving your items that actually call the DB?
I believe you should move the responsibility for writing/reading encrypted values to the calling service (i.e a repository implementation) instead of the BsonSerializer.
It would make sense to me that encryption/decryption is part of the persistence layer and something not handled in the application when needed.
Your implementation targets only the specified property you want to serialize. It doesn't make sense that it creates another property.
A second thought is that your suggested approach with properties that change value based on Decrypt() probably isn't a good idea since it makes your code unpredictable and hard to read. Make your properties dead simple.
What extra security in your code does it really give you if you can decrypt properties by just calling a method anyway?
If you still need to have a Decrypt() would suggest that you create methods for decrypting that return the decrypted value like GetUnencryptedCode() etc, it could just as well be an extension method but still not a readable property.
You should also be looking into using SecureString depending on your use case.

Roslyn Check If Field Declaration has been assigned to

I'm writing an app which converts keys to use resources from a RESX File. This code was working with local variables before:
public static void AnalyzeConstDeclaration(SyntaxNodeAnalysisContext context)
{
var fieldDeclaration = (FieldDeclarationSyntax)context.Node;
if (false == IsValidFieldDeclaration(context, fieldDeclaration))
{
return;
}
var firstVariable = fieldDeclaration.Declaration.Variables.FirstOrDefault();
var dataFlowAnalysis = context.SemanticModel.AnalyzeDataFlow(firstVariable);
var variableSymbol = context.SemanticModel.GetDeclaredSymbol(firstVariable);
if (dataFlowAnalysis.WrittenOutside.Contains(variableSymbol))
{
return;
}
var firstSymbol = context.SemanticModel.GetDeclaredSymbol(firstVariable);
context.ReportDiagnostic(Diagnostic.Create(Rule, context.Node.GetLocation(), firstSymbol.Name));
}
However when I try to get the dataFlowAnalysis I receive an error:
Additional information: statementOrExpression is not a StatementSyntax or an ExpressionSyntax.
How can Ideally just need to see if anyone has written to this variable outside of the declaration.
DataFlow works by analyzing order of execution within a single method.
It doesn't make sense for class-level fields.
Instead, you should use a simple syntax visitor (or SymbolFinder) to search the entire class for assignments to the field.
You'll probably also want to check whether it's ever passed as a ref parameter.

Text template custom host: how to implement ResolveDirectiveProcessor

Im trying to use this example from msdn on how to create a custom host for text template generation.
The CustomCmdLineHost class implements the ITextTemplatingEngineHost interface but not completely, the ResolveDirectiveProcessor is not implemented and it throws each time an exception wich is normal. Here is the ResolveDirectiveProcessor method:
public Type ResolveDirectiveProcessor(string processorName)
{
//This host will not resolve any specific processors.
//Check the processor name, and if it is the name of a processor the
//host wants to support, return the type of the processor.
//---------------------------------------------------------------------
if (string.Compare(processorName, "XYZ", StringComparison.OrdinalIgnoreCase) == 0)
{
//return typeof();
}
//This can be customized to search specific paths for the file
//or to search the GAC
//If the directive processor cannot be found, throw an error.
throw new Exception("Directive Processor not found");
}
and processorName passsed to this function is "T4VSHost",
The question now:
What is the type of "T4VSHost" to return in this method ?
P.S.: i tried "Microsoft.Data.Entity.Design.VisualStudio.Directives.FallbackT4VSHostProcessor" but it seems that it doesnt exist in any namespace.
It appears that the only way is to create that type. how ? by creating a class (lets call it FallbackT4VSHostProcessor) that inherits from the DirectiveProcessor abstract class which lives in the Microsoft.VisualStudio.TextTemplating namespace (the only example i found in the internet is Here). then we need to return the type of FallbackT4VSHostProcessor in the ResolveDirectiveProcessor like this:
Type ITextTemplatingEngineHost.ResolveDirectiveProcessor(string processorName)
{
if (string.Compare(processorName, "T4VSHost", StringComparison.OrdinalIgnoreCase) == 0)
{
return typeof(FallbackT4VSHostProcessor);
}
throw new Exception("Directive Processor not found");
}
I hope this will help someone someday.

IIS Application : How to get an unique ID

I have an application that manage IIS Application instances so I am looking for a kind of GIUD to identify each applications. This GUID must be created when the application is deployed in IIS and must be persistent to IIS/Windows updates/restarts.
I did not need the use of Microsoft.Web.Administration: I want a simple way, for each IIS application, it returns its unique ID (by a method called within it).
Here is an example of what I'm looking for and I'd like to have an unique id returned by this.????? :
public class MvcApplication : System.Web.HttpApplication
{
string myUniqueID {
get { return this.?????; }
}
}
Thanks for help.
HostingEnvironment.ApplicationID
https://msdn.microsoft.com/en-us/library/system.web.hosting.hostingenvironment.applicationid(v=vs.110).aspx
I had to do something similar.
Read the web.config file for a HostId setting. Preferably split your configuration file into two, with one config file that is local to the install, and doesn't get replaced upon upgrading to a new version of the website.
If the HostId value doesn't exist in the web.config, call Guid.NewGuid() to generate a new value.
Save the new value to the web config, preferably in the local section/file.
Return the value.
Here is some psuedo-code:
public Guid HostId
{
get
{
var result = GetSetting(ConfigFileLocalSettingList.HostId).TryToGuid();
if (result == null)
{
result = Guid.NewGuid();
SetSetting(ConfigFileLocalSettingList.HostId, result.ToString());
Save();
}
return result.Value;
}
}
You can use the assembly GUID for this purpose: In AssemblyInfo.cs, you can find
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("307E39B9-2C41-40CF-B29F-84C8BBCD6519")]
To read this value, you can use:
public static string AssemblyGUID
{
get {
var assembly = Assembly.GetExecutingAssembly();
var attribute = (System.Runtime.InteropServices.GuidAttribute)assembly.GetCustomAttributes(typeof(System.Runtime.InteropServices.GuidAttribute), true)[0];
var GUID = attribute.Value;
return GUID;
}
}
which is taken from another SO answer (you can find it here).
And if it is required, Visual Studio allows you to create a new GUID via menu Tools -> Create GUID - if you need a different one.
Or in C# you simply use
var newGuid=(Guid.NewGuid()).ToString();
Console.WriteLine(newGuid);
to create a new GUID.

Why do I have to manually create ExpandoObject to properly use the dynamic keyword?

I was looking at the question Use 'dynamic' throw a RuntimeBinderException. I face a similar problem:
Basically, I want to create a "HTML helper" in ASP.NET MVC that uses dynamic arguments, akin to the htmlArguments parameter for many of the existing helpers (more code below):
public BootstrapCell(Action<string> emitContentAction, dynamic args)
View:
#using (grid.Cell(ViewContext.Writer.Write, new {Position = 4}))
{
<p>zomg!</p>
}
However in the naive approach, i get RuntimeBinderException thrown at me, declaring that 'object' does not contain a definition for 'Position', even though when debugging and hovering over the _args variable, it clearly does have a Position property.
The caller and the callee are in separate assemblies. Why is that problem happening?
(The solution to that has been shown in the same question: Manually create an ExpandoObject to hold the args.)
Implementation:
public class Cell
{
private readonly string _tagName;
private dynamic _args;
private Action<string> EmitContentAction;
public BootstrapCell(Action<string> emitContentAction, dynamic args) : DisposableBaseClass
{
_args = args;
EmitContentAction = emitContentAction;
OnContextEnter();
}
protected void OnContextEnter()
{
var sb = new StringBuilder("<");
sb.Append(_tagName);
if (_args.Position > 0)
{
sb.Append(" class=\"offset");
sb.Append(args.Position);
sb.Append("\"");
}
sb.Append(">");
EmitContentAction(sb.ToString());
}
}
[Edited to make clearer that my problem arises when "obviously" the Position property is set. I am aware that if the property never was defined in the first place, an exception must be raised.]
That code is fatally flawed.
It does work, as long as you specify that property:
void Bar()
{
Foo(new {Position = 0});
}
void Foo(dynamic args)
{
Console.WriteLine(args.Position);
}
That will output 0, it will not throw a RuntimeBinderException.
But the purpose of such code is the possibility for the caller to specify only the properties needed and omit the rest.
You are trying to check for this omission via if(args.Position != null). But that doesn't work, it already requires Position to exist.
When you have a look at the routing API of ASP.NET that also supports those anonymous configuration objects you will notice that the type of the parameter is object and not dynamic.
Using object instead of dynamic will enable your API to be used across assembly boundaries.
So how does it work?
Just like in the linked answer, you need to manually create a dictionary of the properties. Whether you use a plain old Dictionary<string, object> or an ExpandoObject is a matter of preference.
Using ExpandoObject will make your code a bit simpler to read and write, but it is not required.
About the actual exception you are getting:
Please note that it tells you it can't find the Position property on object. If it would be an anonymous type that was missing the Position property the exception message wouldn't refer to object but to an anonymous type. Something like this:
'<>f__AnonymousType0' does not contain a definition for 'Position'

Categories

Resources