How to resolve FXCop Error - CA3056 - fxcop

I have following code:
var configuration = new XmlDocument();
configuration.Load(filePath);
Fxcope giving following error:
Using this overload of System.Xml.XmlDocument/XmlDataDocument Load()
method is potentially unsafe, replace with the Load() overload that
takes an XmlReader instance
Any suggestions or any guidance? And when I replace with XmlReader do I need to use Using(try/catch/finally) to dispose XmlReader?

Related

WCF Read stream changes the behaviour of a WebFaultException

We have the following web method:
public void RawData(string dataItemName, Stream sourceStream)
{
StreamReader reader = new StreamReader(sourceStream);
{
string data = reader.ReadToEnd();
throw new WebFaultException<string>("error", System.Net.HttpStatusCode.BadRequest);
}
}
and is defined as follows:
[WebInvoke(Method = "POST", UriTemplate= "RawData/{dataItemName}", ResponseFormat = WebMessageFormat.Xml)]
[OperationContract]
[FaultContract(typeof(LoginFaultInfo))]
[FaultContract(typeof(SecurityFaultInfo))]
[FaultContract(typeof(RequestFaultInfo))]
[Description("Sets data for the specified item")]
void RawData(string dataItemName, Stream dataStream);
This correctly generates the exception in the client.
However, if this code is changed as follows:
public void RawData(string dataItemName, Stream sourceStream)
{
using (StreamReader reader = new StreamReader(sourceStream))
{
string data = reader.ReadToEnd();
}
throw new WebFaultException<string>("error", System.Net.HttpStatusCode.BadRequest);
}
Then the client gets a 202 Accepted Status rather than a fault exception.
Does anyone know why this is the case? Reading and disposing of the stream has changed the behaviour somehow,
Do not use "using" in WCF Client.
You can check Microsoft documentation for instructions.
Close and Abort release resources safely when network connections have dropped
The C# "using" statement results in a call to Dispose(). This is the
same as Close(), which may throw exceptions when a network error
occurs. Because the call to Dispose() happens implicitly at the
closing brace of the "using" block, this source of exceptions is
likely to go unnoticed both by people writing the code and reading the
code. This represents a potential source of application errors.
I think you can use the Microsoft recommended way of handling WCF client calls.For more detail see: Expected Exceptions.

.NET Core pdf downloader "No output formatter was found for content types 'application/pdf'..."

I'm creating a .NET Core 3.1 web api method to download a pdf for a given filename. This method is shared across teams where their client code is generated using NSwag.
I recently changed produces attribute to Produces("Application/pdf") from json, this change is required so other teams can generate valid client code. However since this change, I haven't been able to download any files from this method. Requests to download documents return with a 406 error (in Postman) and the following error is logged to the server event viewer.
No output formatter was found for content types 'application/pdf, application/pdf' to write the response.
Reverting the produced content-type to 'application/json' does allow documents to be downloaded, but as mentioned, this value is required to be pdf.
Any suggestions would be greatly appreciated.
Method:
[HttpGet("{*filePath}")]
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[Produces("Application/pdf")]
public async Task<ActionResult> GetDocument(string fileName) {
RolesRequiredHttpContextExtensions.ValidateAppRole(HttpContext, _RequiredScopes);
var memoryStream = new MemoryStream();
var memoryStream = new MemoryStream();
using (var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize: 4096, useAsync: true)) {
stream.CopyTo(memoryStream);
}
memoryStream.Seek(offset: 0, SeekOrigin.Begin);
return new FileStreamResult(memoryStream, "Application/pdf");
}
I just came across the same error and after some investigation I found out that the cause of the exception was indeed in the model binding error. You already wrote about it in your answer, but on closer inspection it became obvious that the reason was not related to binding itself, rather to the response body.
Since you specified [Produces("application/pdf")] the framework assumes this content type is the only possible for this action, but when an exception is thrown, you get application/json containing error description instead.
So to make this work for both "happy path" and exceptions, you could specify multiple response types:
[Produces("application/pdf", "application/json")]
public async Task<ActionResult> GetDocument(string fileName)
{
...
}
I'am using
public asnyc Task<IActionResult> BuildPDF()
{
Stream pdfStream = _pdfService.GetData();
byte[] memoryContent = pdfStream.ToArray();
return File(memoryContent, "application/pdf");
}
and it works. Could you please try?
The issue was caused by renaming the method parameter and not updating [HttpGet("{*filePath}")] to [HttpGet("{*fileName}")]
I had the same error, it is very confusing in some cases.
I got this error after adding new parameter of type int[] to my method forgetting [FromQuery] attribute for it.
After adding [FromQuery] attribute error gone.

Creating WCF service by determining type at runtime

I am trying to create a WCF service without knowing its type/interface at runtime. To do this, I use ChannelFactory. ChannelFactory is a generic class so I need to use Type.MakeGenericType. The type I pass to MakeGenericType is from a list of interfaces I previously gathered with reflection by searching some assemblies.
Ultimately, I call MethodInfo.Invoke to create the object. The object is created just fine, but I cannot cast it to the proper interface. Upon casting, I receive the following error:
"Unable to cast transparent proxy to type 'Tssc.Services.MyType.IMyType'"
After some experimenting, I have found that the interface/type passed to MakeGenericType seems to be the problem. If I substitute the interface in my list with the actual interface, then everything works fine. I have combed through the two objects and cannot see a difference. When I modify the code to produce both types, comparing them with Equals returns false. It is unclear to me whether Equals is just checking that they are referring to the same object (not) or thety are checking all properties, etc.
Could this have something to do with how I gathered my interfaces (Reflection, saving in a list...)? A comparison of the objects seems to indicate they are equivalent. I printed all properties for both objects and they are the same. Do I need to dig deeper? If so, into where?
// createService() method
//*** tried both of these interfaces, only 2nd works - but they seem to be identical
//Type t = interfaces[i]; // get type from list created above - doesn't work
Type t = typeof(Tssc.Services.MyType.IMyType); // actual type - works OK
// create ChannelFactory type with my type parameter (t)
Type factoryType = typeof(ChannelFactory<>);
factoryType = factoryType.MakeGenericType(new Type[] { t });
// create ChannelFactory<> object with two-param ctor
BasicHttpBinding binding = new BasicHttpBinding();
string address = "blah blah blah";
var factory = Activator.CreateInstance(factoryType, new object[] { binding, address });
// get overload of ChannelFactory<>.CreateChannel with no parameters
MethodInfo method = factoryType.GetMethod("CreateChannel", new Type[] { });
return method.Invoke(factory, null);
//--------------- code that calls code above and uses its return
object ob = createService();
//*** this cast fails
Tssc.Services.MyType.IMyType service = (Tssc.Services.MyType.IMyType)ob;
Ok, I understand whats happening here - the problem is relating to loading the same assembly being effectively loaded twice - once via a reference, and once via the assembly load command. What you need to do is change the place where you load your assembly, and check to see if it already exists in the current AppDomain, like this maybe:
Assembly assembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(a => a.GetName().Name.Equals("ClassLibrary1Name"));
if (assembly == null)
{
assembly = System.Reflection.Assembly.LoadFile("path to your assembly");
}
//do your work here
This way if the assembly is already loaded into memory, it'll use that one.

Serialization error with Elasticsearch NEST/C#

I'm using NEST to index my objects and I'm running into a Newtonsoft error on serialization. One of my objects has a self referencing loop. Would there be a way for me to access the JsonSerializer and change how it handles self-references without having to modify the source code?
You can register custom converters on your client:
public void AddConverter(JsonConverter converter)
{
this.IndexSerializationSettings.Converters.Add(converter);
this.SerializationSettings.Converters.Add(converter);
}
This might be of help.
There is no direct way to alter the JsonSerializerSettings used in the client though.
There is a new api now, take a look at:
var cs2 = new ConnectionSettings(new Uri("http://localhost:9200"))
.SetJsonSerializerSettingsModifier(settings => settings.TypeNameHandling = TypeNameHandling.None)
.EnableTrace();
Thanks for adding the support!

How to read the System.ServiceModel.Message?

I came across this situation.
Main Function:
Message msg = Message.CreateMessage(MessageVersion.Default, "Process");
String xmlData ="<Name>Navin</Name>";
Byte[] ba = Encoding.ASCII.GetBytes(xmlData);
MemoryStream ms = new MemoryStream(ba);
XmlWriter xw = XmlWriter.Create(ms);
msg.WriteBody(xw);
readMessage(msg);
In readMessage(Message msg):
XmlDictionaryReader xdr = msg.GetReaderAtBodyContents();
WHen i do this i am getting this error.
Unhandled Exception: System.InvalidOperationException: This message cannot suppo
rt the operation because it has been written.
How to overcome this.
Waiting for response.
Thanks in advance.
According to MSDN Message.GetReaderAtBodyContents Method, you can't access the message body once it's been read or written - it can only be accessed once. You need to use 'CreateBufferedCopy' to access a message multiple times.
I didn't find any examples in the MSDN documentation, but it looks like you'd need to create a MessageBuffer instance via Message.CreateBufferedCopy, and then you can use the MessageBuffer's CreateMessage method to gain access to the contents of the buffer.
See:
Message.CreateBufferedCopy Method
MessageBuffer Class
MessageBuffer.CreateMessage Method