I am building a WCF client to access a vendor web service. The service uses IssuedTokenOverTransport, SymmetricKey, and expects SAML. I have the request working, but the response back from the service includes a SignatureConfirmation element in the WS-Security header. My C# client chokes on this "signature confirmation is not expected in the security header" and I don't see a way to either ignore or process this element. It seems the only way to get near the handling of SignatureConfirmation in WCF is to abandon the IssuedTokenOverTransport binding and use something else, but this doesn't seem to be an option because the service requires this binding type. Is this a bug in WCF?
I solved this by using a custom Message Encoder. See this article from Carlos Figueroa for background:
http://blogs.msdn.com/b/carlosfigueira/archive/2011/11/09/wcf-extensibility-message-encoders.aspx
Essentially, the encoder can look for the SignatureConfirmation element in the incoming message and remove it from the header. The key piece of code is this private method that is called from the ReadMessage overrides:
private MemoryStream ProcessMemoryStream(Stream inputStream, bool dispose)
{
StreamWriter xmlStream = null;
var outputStream = new MemoryStream();
bool continueFilter = false;
try
{
xmlStream = new StreamWriter(outputStream);
using (var reader = XmlReader.Create(inputStream))
{
using (
var writer = XmlWriter.Create(xmlStream,
new XmlWriterSettings() {ConformanceLevel = ConformanceLevel.Auto}))
{
while (reader.Read())
{
if (reader.LocalName.Equals("SignatureConfirmation") &&
reader.NamespaceURI.Equals(
"http://docs.oasis-open.org/wss/oasis-wss-wssecurity-secext-1.1.xsd"))
{
if (!reader.IsEmptyElement) continueFilter = reader.IsStartElement();
}
else if (reader.LocalName.Equals("Signature") &&
reader.NamespaceURI.Equals("http://www.w3.org/2000/09/xmldsig#"))
{
if (!reader.IsEmptyElement) continueFilter = reader.IsStartElement();
}
else if (continueFilter)
{
// continue to next node
}
else
XmlHelper.WriteShallowNode(reader, writer);
}
writer.Flush();
}
reader.Close();
}
outputStream.Position = 0;
return outputStream;
}
catch (Exception ex)
{
// handle error
throw;
}
finally
{
if (xmlStream != null && dispose) xmlStream.Dispose();
}
}
The Xml Helper:
internal static class XmlHelper
{
internal static void WriteShallowNode(XmlReader reader, XmlWriter writer)
{
if (reader == null)
{
throw new ArgumentNullException("reader");
}
if (writer == null)
{
throw new ArgumentNullException("writer");
}
switch (reader.NodeType)
{
case XmlNodeType.Element:
writer.WriteStartElement(reader.Prefix, reader.LocalName, reader.NamespaceURI);
writer.WriteAttributes(reader, true);
if (reader.IsEmptyElement)
{
writer.WriteEndElement();
}
break;
case XmlNodeType.Text:
writer.WriteString(reader.Value);
break;
case XmlNodeType.Whitespace:
case XmlNodeType.SignificantWhitespace:
writer.WriteWhitespace(reader.Value);
break;
case XmlNodeType.CDATA:
writer.WriteCData(reader.Value);
break;
case XmlNodeType.EntityReference:
writer.WriteEntityRef(reader.Name);
break;
case XmlNodeType.XmlDeclaration:
case XmlNodeType.ProcessingInstruction:
writer.WriteProcessingInstruction(reader.Name, reader.Value);
break;
case XmlNodeType.DocumentType:
writer.WriteDocType(reader.Name, reader.GetAttribute("PUBLIC"), reader.GetAttribute("SYSTEM"),
reader.Value);
break;
case XmlNodeType.Comment:
writer.WriteComment(reader.Value);
break;
case XmlNodeType.EndElement:
writer.WriteFullEndElement();
break;
}
}
}
Related
This api controller is used to return a pdf stream to display in an html object tag
using AspNetCore.Reporting;
using Microsoft.AspNetCore.Mvc;
[HttpGet, Route("ProcedureRangeForm")]
public IActionResult ProcedureRangeForm(string procedureRangeId, byte procedureTypeId)
{
int extension = 1;
var _reportPath = "";
switch (procedureRangeId)
{
case "1":
_reportPath = #"Reports\ProcedureRangeForm1.rdlc";
break;
case "2":
_reportPath = #"Reports\ProcedureRangeForm2.rdlc";
break;
case "3":
_reportPath = #"Reports\ProcedureRangeForm3.rdlc";
break;
default:
// code block
break;
}
//Employee employee = _context.Employees.FirstOrDefault(x => x.Id == "41")!;
ProcedureType procedureType = _context.ProcedureTypes.FirstOrDefault(x => x.Id == procedureTypeId);
//RelationDegree relationDegree = _context.RelationDegrees.FirstOrDefault(x => x.Id == 1)!;
var reportParams1 = new Dictionary<string, string>();
var reportParams2 = new Dictionary<string, string>();
var reportParams3 = new Dictionary<string, string>();
reportParams1.Add("UnitCode", "UnitCode");
reportParams1.Add("ProcedureType", procedureType!.Name!);
reportParams2.Add("ProcedureType", procedureType!.Name!);
reportParams3.Add("ProcedureType", procedureType!.Name!);
//reportParams1.Add("Attachments", "");
LocalReport localReport = new LocalReport(_reportPath);
FileContentResult fileContentResult;
MemoryStream memory = new();
try
{
ReportResult result = null!;
switch (procedureRangeId)
{
case "1":
result = localReport.Execute(RenderType.Pdf, extension, parameters: reportParams1);
break;
case "2":
result = localReport.Execute(RenderType.Pdf, extension, parameters: reportParams2);
break;
case "3":
result = localReport.Execute(RenderType.Pdf, extension, parameters: reportParams3);
break;
default:
// code block
break;
}
byte[] file = result.MainStream;
fileContentResult = new FileContentResult(file, "application/pdf");
}
catch (Exception e)
{
Console.WriteLine("{0} Exception caught.", e);
return Content(HttpStatusCode.InternalServerError.ToString(), e.Message);
}
finally
{
}
return fileContentResult;
}
I want to call this api more than once with varient parameters. when i call once to display ProcedureRangeForm1.rdlc it run successfully , but when i call again to display ProcedureRangeForm2.rdlc throw this exception
System.FormatException: 'The header contains invalid values at index 0: 'An error occurred during local report processing.;The definition of the report 'Reports\ProcedureRangeForm1.rdl' is invalid. An unexpected error occurred in Report Processing. The process cannot access the file 'hdsktzjh.err' because it is being used by another process.''
After a lot of research, I found a solution to my question:
First, I used nuget package Tmds.ExecFunction by Execute a function in a separate process
as in this link
But I didn't get what I wanted
And then I replaced the library AspNetCore.Reporting by ReportViewerCore.NETCore
as in this link
the problem solved as this code
using Microsoft.Reporting.NETCore;
[Route("api/[controller]")]
[ApiController]
public class ProcedureRangeFormsController : ControllerBase
{
private readonly HousingDbContext _context;
public ProcedureRangeFormsController(HousingDbContext context)
{
_context = context;
}
// GET api/values
[HttpGet, Route("ProcedureRangeForm/{procedureRangeId}/{procedureTypeId}")]
public IActionResult ProcedureRangeForm(string procedureRangeId, string procedureTypeId)
{
var reportPath = "";
switch (procedureRangeId)
{
case "1":
reportPath = "TaxHousing.Reports.ProcedureRangeForm1.rdlc";
break;
case "2":
reportPath = "TaxHousing.Reports.ProcedureRangeForm2.rdlc";
break;
case "3":
reportPath = "TaxHousing.Reports.ProcedureRangeForm3.rdlc";
break;
default:
// code block
break;
}
using var rs = Assembly.GetExecutingAssembly().GetManifestResourceStream(reportPath);
var localReport = new Microsoft.Reporting.NETCore.LocalReport();
localReport.LoadReportDefinition(rs);
var reportParams1 = new[] {
new ReportParameter("ProcedureType", "ProcedureType1"),
new ReportParameter("UnitCode", "UnitCode1")
};
var reportParams2 = new[] {
new ReportParameter("ProcedureType", "ProcedureType2")
};
var reportParams3 = new[] {
new ReportParameter("ProcedureType", "ProcedureType3")
};
byte[] file = null;
switch (procedureRangeId)
{
case "1":
localReport.SetParameters(reportParams1);
break;
case "2":
localReport.SetParameters(reportParams2);
break;
case "3":
localReport.SetParameters(reportParams3);
break;
default:
// code block
break;
}
try
{
file = localReport.Render("PDF");
}
catch (Exception e)
{
Console.WriteLine("{0} Exception caught.", e);
return Content(HttpStatusCode.InternalServerError.ToString(), e.Message);
}
return new FileContentResult(file, "application/pdf");
}
}
I need to find the tag 200 using the service trace viewer, it looks something like that!
<SOAP-ENV:Body xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="id-14799">
<ns2:SendInvoice xmlns:ns2="http://www.zadrwan.com/services/" xmlns:ns3="http://www.zadrwan.com/services/DocumentSendTo" xmlns:ns4="http://www.zadrwan.com/services/VersionRequest">
<ns2:Response>200</ns2:Response>
<ns2:Comments>Success!.</ns2:Comments>
</ns2:SendInvoice>
when running the webservice does the Trace and writes an E2ETraceEvent the first one I don't need it, but the second one E2ETraceEvent (request) is the one I need and where is the
I found some code on this page monitoring-and-reading-svclog-file
my code is like this:
XmlReader reader = XmlReader.Create(stream, settings);
while (reader.Read())
{
switch (reader.NodeType)
{
case XmlNodeType.Element:
if (reader.Name == "E2ETraceEvent")
{
XmlReader subReader = reader.ReadSubtree();
while (subReader.Read())
{
switch (reader.NodeType)
{
case XmlNodeType.Element:
while (reader.Name == "Body")
{
Console.WriteLine(subReader.ReadOuterXml());
}
break;
}
}
}
break;
}
}
how do i catch the second one, with the tag that contains n2 response ??
You need to add the namespace. Something like:
using (XmlReader reader = XmlReader.Create(new StringReader(xml)))
{
XmlNamespaceManager nsmanager = new XmlNamespaceManager(reader.NameTable);
nsmanager.AddNamespace("ns2", "http://www.zadrwan.com/services/");
while (reader.Read())
{
switch (reader.Name)
{
case "ns2:Response":
Console.WriteLine(reader.Name);
Console.WriteLine(reader.ReadInnerXml());
break;
}
}
}
We are getting false positives while using rule S2538 in the following code
EventLogLevel[] eventLevels = null;
bool reachedEnd = false;
while(!reachedEnd && jsonReader.Read())
{
switch(jsonReader.TokenType)
{
case JsonToken.PropertyName:
string propertyName = jsonReader.Value.ToString();
switch(propertyName)
{
case nameof(EventLevels):
eventLevels = EventSettingsJson.ParseEventLogLevelsArray(nameof(EventLevels), jsonReader);
break;
default:
throw new JsonParserException($"Invalid property: {propertyName}");
}
break;
case JsonToken.EndObject:
reachedEnd = true;
break;
default:
throw new JsonParserException($"Unexpected Token Type while parsing json properties. TokenType: {jsonReader.TokenType}");
}
}
if(eventLevels != null)
{
return new EventLogCollectionSettings(eventLogName, eventLevels);
}
The last if (eventLevels != null) shows the warning with the message:
[Change this condition so that it does not always evaluate to
"false"].
I couldn't create a testcase to reproduce it.
We know about this limitation in our data flow analysis engine. It's related to this ticket: https://jira.sonarsource.com/browse/SLVS-1091. We have no fix for it yet.
I am using FastReport in ASP.net MVC. I wrote some code for removing the report title when exporting to Excel. It works properly. But sometimes the report is shown and after that export method is called; in this case when I push the Next Page button in FastReport's toolbar, I see that the report title was removed. I wrote this:
FastReport.Utils.Config.WebMode = true;
ExportBase export = null;
var webReportExport = new WebReport();
//keep werreport object in tempdata in first loading of report for using it to export later
webReportExport.Report = TempData["WebReport"] as FastReport.Report;
webReportExport.Report.FindObject("PageHeader1").Delete();
webReportExport.Report.FindObject("PageFooter1").Delete();
TempData.Keep("WebReport");
ViewBag.WebReport = TempData["WebReport"] as FastReport.Report;
if (webReportExport.Report.Prepare())
{
switch (exportType)
{
case "pdf": export = new FastReport.Export.Pdf.PDFExport(); break;
case "excel": export = new FastReport.Export.OoXML.Excel2007Export() ; break;
case "word": export = new FastReport.Export.OoXML.Word2007Export(); break;
case "rtf": export = new FastReport.Export.RichText.RTFExport(); break;
default:
break;
}
export.ShowProgress = false;
MemoryStream strm = new MemoryStream();
webReportExport.Report.Export(export, strm);
webReportExport.Dispose();
export.Dispose();
strm.Position = 0;
var currentDate = PersianDate.Parse(PersianDateConverter.ToPersianDate(DateTime.Now).ToString()).ToString("swt");
var reportName = TempData["reportName"] + currentDate;
switch (exportType)
{
case "pdf": return File(strm, "application/pdf", reportName+".pdf"); break;
case "excel": return File(strm, "application/ms-excel", reportName+".xlsx"); break;
case "word": return File(strm, "application/vnd.openxmlformats-officedocument.wordprocessingml.document",reportName+ ".docx"); break;
case "rtf": return File(strm, "application/rtf", reportName+".rtf"); break;
default:
break;
}
}
return null;
I am trying to build a regex parser for a single XML block.
I know people will say that Regex is not a good plan for xml, but I am working with stream data and I just need to know if a complete xml block has been broadcast and is sitting in the buffer.
I am trying to handle for anything between the Opening and closing blocks of the XML and any data in parameters of the main block header.
My example code is below the broken down Regular Expression, if anyone has any input on how to make this as comprehensive as possible I would greatly appreciate it.
Here is my regular expression formatted for visual aid.
I am balancing the group, as well as the group and validating that they do not exist at the end of the expression segments.
/*
^(?<TAG>[<]
(?![?])
(?<TAGNAME>[^\s/>]*)
)
(?<ParamData>
(
(\"
(?>
\\\"|
[^"]|
\"(?<quote>)|
\"(?<-quote>)
)*
(?(quote)(?!))
\"
)|
[^/>]
)*?
)
(?:
(?<HASCONTENT>[>])|
(?<-TAG>
(?<TAGEND>/[>])
)
)
(?(HASCONTENT)
(
(?<CONTENT>
(
(?<inTAG>[<]\<TAGNAME>)(?<-inTAG>/[>])?|
(?<-inTAG>[<]/\<TAGNAME>[>])|
([^<]+|[<](?![/]?\<TAGNAME>))
)*?
(?(inTAG)(?!))
)
)
(?<TAGEND>(?<-TAG>)[<]/\<TAGNAME>[>])
)
(?(TAG)(?!))
*/
Within my class, I expect that any Null object returned means there was no xml block on the queue.
Here is the class I am using.
(I used a literal string (#"") to limit the escape requirements, All " characters were replaced with "" to format properly.
public class XmlDataParser
{
// xmlObjectExpression defined below to limit code highlight errors
private Regex _xmlRegex;
private Regex xmlRegex
{
get
{
if (_xmlRegex == null)
{
_xmlRegex = new Regex(xmlObjectExpression);
}
return _xmlRegex;
}
}
private string backingStore = "";
public bool HasObject()
{
return (backingStore != null) && xmlRegex.IsMatch(backingStore);
}
public string GetObject()
{
string result = null;
if (HasObject())
{
lock (this)
{
Match obj = xmlRegex.Match(backingStore);
result = obj.Value;
backingStore = backingStore.Substring(result.Length);
}
}
return result;
}
public void AddData(byte[] bytes)
{
lock (this)
{
backingStore += System.Text.Encoding.Default.GetString(bytes);
}
}
private static string xmlObjectExpression = #"^(?<TAG>[<](?![?])(?<TAGNAME>[^\s/>]*))(?<ParamData>((\""(?>\\\""|[^""]|\""(?<quote>)|\""(?<-quote>))*(?(quote)(?!))\"")|[^/>])*?)(?:(?<HASCONTENT>[>])|(?<-TAG>(?<TAGEND>/[>])))(?(HASCONTENT)((?<CONTENT>((?<inTAG>[<]\<TAGNAME>)(?<-inTAG>/[>])?|(?<-inTAG>[<]/\<TAGNAME>[>])|([^<]+|[<](?![/]?\<TAGNAME>)))*?(?(inTAG)(?!))))(?<TAGEND>(?<-TAG>)[<]/\<TAGNAME>[>]))(?(TAG)(?!))";
}
Just use XmlReader and feed it a TextReader. To read streams, you want to change the ConformanceLevel to Fragment.
XmlReaderSettings settings = new XmlReaderSettings();
settings.ConformanceLevel = ConformanceLevel.Fragment;
using (XmlReader reader = XmlReader.Create(tr,settings))
{
while (reader.Read())
{
switch (reader.NodeType)
{
// this is from my code. You'll rewrite this part :
case XmlNodeType.Element:
if (t != null)
{
t.SetName(reader.Name);
}
else if (reader.Name == "event")
{
t = new Event1();
t.Name = reader.Name;
}
else if (reader.Name == "data")
{
t = new Data1();
t.Name = reader.Name;
}
else
{
throw new Exception("");
}
break;
case XmlNodeType.Text:
if (t != null)
{
t.SetValue(reader.Value);
}
break;
case XmlNodeType.XmlDeclaration:
case XmlNodeType.ProcessingInstruction:
break;
case XmlNodeType.Comment:
break;
case XmlNodeType.EndElement:
if (t != null)
{
if (t.Name == reader.Name)
{
t.Close();
t.Write(output);
t = null;
}
}
break;
case XmlNodeType.Whitespace:
break;
}
}
}