First, Let me explain why I need do this.
I have an inbound port with EDIReceive Pipeline configuration. it receives EDI X12 837I files and disassemble these files to 837I messages.
There's one file failed with error description below:
The following elements are not closed: ns0:X12_00501_837_I. Line 1, position 829925.
It looks like the incoming file have some structure issue. Making the disassembler cannot produce the message correctly. But the error itself don't help to locate the issue. Also, no TA1 and 999 generated to help us locate the issue.
So I created a little console application using the Pipeline Component Test Library try to run this file through the edidisassembler pipeline component to see if I can find what cause the error.
The code is pretty straightforward:
namespace TestEDIDasm
{
using System;
using System.IO;
using Microsoft.BizTalk.Edi.Pipelines;
using Microsoft.BizTalk.Message.Interop;
using Winterdom.BizTalk.PipelineTesting;
using Microsoft.BizTalk.Edi.BatchMarker;
class Program
{
static void Main(string[] args)
{
var ediDasmComp = new EdiDisassembler();
ediDasmComp.UseIsa11AsRepetitionSeparator = true;
ediDasmComp.XmlSchemaValidation = true;
var batchMaker = new PartyBatchMarker();
IBaseMessage testingMessage = MessageHelper.LoadMessage(#"c:\temp\{1C9420EB-5C54-43E5-9D9D-7297DE65B36C}_context.xml");
ReceivePipelineWrapper testPipelineWrapper = PipelineFactory.CreateEmptyReceivePipeline();
testPipelineWrapper.AddComponent(ediDasmComp, PipelineStage.Disassemble);
testPipelineWrapper.AddComponent(batchMaker, PipelineStage.ResolveParty);
var outputMessages = testPipelineWrapper.Execute(testingMessage);
if (outputMessages.Count <= 0)
{
Console.WriteLine("No output message");
Console.ReadKey();
return;
}
var msg = outputMessages[0];
StreamReader sr = new StreamReader(msg.BodyPart.Data);
Console.WriteLine(sr.ReadToEnd());
Console.ReadKey();
}
}
}
I added some breakpoint but end up with following errors in message context:
"X12 service schema not found"
Clearly, the EDIDisassembler component rely on some other stuff to do its job.
Now goes to my question:
Is there anyway to make EdiDisassembler working in testing
environment?
If there any other way to debug/trace the disassembler component
processing file other than Pipeline Component Test Library?
Theoretically, sure, but you have to replicate a lot of engine context that exists during Pipeline execution. The EDI components have issues running inside Orchestrations so it's likely a pretty tall order.
Have you tried a Preserve Interchange Pipeline with the Fallback Settings? That's about as simple as you can get with the EDI Disassembler.
Related
I have an ASP.NET 4.7 web project where there is a Quartz.NET scheduler implemented.
I've read that Quartz.NET is using Common.Logging abstraction, but I don't know what it really means...
In order to avoid my default application log to be spammed from Quartz messages, I have configured programmatically the NLog settings, in the following way:
var config = new NLog.Config.LoggingConfiguration();
var logfile = new NLog.Targets.FileTarget("logfile")
{
FileName = "${basedir}/Logs/${logger}_${shortdate}.log",
Layout = "${longdate}|${level:uppercase=true}|${aspnet-request-ip}|${aspnet-request-url}|${callsite}|${message}|${exception:format=tostring}"
};
var logfileQ = new NLog.Targets.FileTarget("logfile")
{
FileName = "${basedir}/Logs/Quartz_${shortdate}.log",
Layout = "${longdate}|${level:uppercase=true}||${message}"
};
config.AddTarget(logfile);
config.AddTarget(logfileQ);
config.AddRule(LogLevel.Error, LogLevel.Fatal, logfileQ, "Quartz*", true);
config.AddRule(LogLevel.Trace, LogLevel.Fatal, logfile, "*");
// Apply config
NLog.LogManager.Configuration = config;
NLog.LogManager.ReconfigExistingLoggers();
Then I add my application logs with the following code:
public class MyApiController : ApiController
{
private static NLog.Logger logger = NLog.LogManager.GetLogger("Application");
[HttpPost]
[Authorize]
public IHttpActionResult Post(DataModel.MyModel m)
{
logger.Warn("Unable to add point {0}: localization missing", m.Name);
}
}
So NLog creates an "application_yyyy-MM-dd.log" file correctly and also a "Quartz_yyyy-MM-dd.log" file with only the error and fatal message levels.
The problem is that it creates also the following three files for Quartz containing all levels:
Quartz.Core.JobRunShell_2020-04-28.log
Quartz.Core.QuartzSchedulerThread_2020-04-28.log
Quartz.Simpl.SimpleJobFactory_2020-04-28.log
It seems like final=true of the first rule is ignored.
Which is the right way to configure it? Should I have to disable something in Quartz?
I finally figured it out.
The added rules must be seen as filters, what doesn't match a filter go to the next rule.
The last one is like "take everything that has not been matching before..."
The main issue in mine rules is the first one that match only the levels Error and Fatal, but all the other levels of Quartz message step into the next rule that writes the log file.
Therefore the rules should be like this:
config.AddRule(LogLevel.Trace, LogLevel.Fatal, logfileQ, "Quartz*", true);
config.AddRule(LogLevel.Trace, LogLevel.Fatal, logfile, "*");
In this way, all the messages, of any levels, coming from Quartz will be written in the quartz_ log file.
To avoid a trace or info level of Quartz to be recorded I should add a third rule to grab also them and placed before the "grab all" rule:
config.AddRule(LogLevel.Warn, LogLevel.Fatal, logfileQ, "Quartz*", true);
config.AddRule(LogLevel.Trace, LogLevel.Info, noLogging, "Quartz*", true);
config.AddRule(LogLevel.Trace, LogLevel.Fatal, logfile, "*");
Where noLogging is a target that doesn't write anywhere or only to console
I have the gRPC server code as below:
public void buildServer() {
List<BindableService> theServiceList = new ArrayList<BindableService>();
theServiceList.add(new CreateModuleContentService());
theServiceList.add(new RemoveModuleContentService());
ServerBuilder<?> sb = ServerBuilder.forPort(m_port);
for (BindableService aService : theServiceList) {
sb.addService(aService);
}
m_server = sb.build();
}
and client code as below:
public class JavaMainClass {
public static void main(String[] args) {
CreateModuleService createModuleService = new CreateModuleService();
ESDStandardResponse esdReponse = createModuleService.createAtomicBlock("8601934885970354030", "atm1");
RemoveModuleService moduleService = new RemoveModuleService();
moduleService.removeAtomicBlock("8601934885970354030", esdReponse.getId());
}
}
While I am running the client I am getting an exception as below:
Exception in thread "main" io.grpc.StatusRuntimeException: UNIMPLEMENTED: Method grpc.blocks.operations.ModuleContentServices/createAtomicBlock is unimplemented
at io.grpc.stub.ClientCalls.toStatusRuntimeException(ClientCalls.java:233)
at io.grpc.stub.ClientCalls.getUnchecked(ClientCalls.java:214)
at io.grpc.stub.ClientCalls.blockingUnaryCall(ClientCalls.java:139)
In the above server class, if I am commenting the line theServiceList.add(new RemoveModuleContentService()); then the CreateModuleContentService service is working fine, also without commenting all the services of RemoveModuleContentService class are working as expected, which means the problem is with the first service when another gets added.
Can someone please suggest how can I add two services to Server Builder.
A particular gRPC service can only be implemented once per server. Since the name of the gRPC service in the error message is ModuleContentServices, I'm assuming CreateModuleContentService and RemoveModuleContentService both extend ModuleContentServicesImplBase.
When you add the same service multiple times, the last one wins. The way the generated code works, every method of a service is registered even if you don't implement that particular method. Every service method defaults to a handler that simply returns "UNIMPLEMENTED: Method X is unimplemented". createAtomicBlock isn't implemented in RemoveModuleContentService, so it returns that error.
If you interact with the ServerServiceDefinition returned by bindService(), you can mix-and-match methods a bit more, but this is a more advanced API and is intended more for frameworks to use because it can become verbose to compose every application service individually.
I had an existing MVC5 web app. I just created a new Unit Test Project and added the following code....
using Microsoft.VisualStudio.TestTools.UnitTesting;
using SomethingApp.Services;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SUT = SomethingApp.Services.ReportingServices; // SUT = System Under Test
namespace SomethingApp.Services.Tests
{
[TestClass]
public class GettingScoreForQuestionShould
{
[TestMethod]
public void ReturnScoreWhenGivenValidData()
{
// Arrange
int eventId = 39;
int questionId = 271;
decimal score;
// Act
score = SUT.GetScoreForQuestion(eventId, questionId);
// Assert
Assert.AreEqual("80",score);
}
}
}
When the method GetScoreForQuestion runs in the normal web app it runs perfect. But, when I run it through the test method I'm getting this error...
Message: Test method SomethingApp.Services.Tests.GettingScoreForQuestionShould.ReturnScoreWhenGivenValidData
threw exception: System.InvalidOperationException: No connection string
named 'myDbContext' could be found in the application config file.
The error is, of course, coming from the method GetScoreForQuestion, which works fine in the normal web app.
I don't understand why I need to add an application config file and this config connection string to the test project. Seems like, since I'm calling the method in the MVC project, that this has the responsibility of making the connection and doing it's thing (which it's doing in the normal course of the app). Am I mistaking something?
And, I tried adding a new application.config file and the connection string to the unit test project, but then the test method won't show up anymore in the Test Explorer after build. Any suggestions? Thanks!
UPDATE ****
Here's the code for GetScoreForQuestion (the offending method, which works in the web app fine, but not when called thru the test method)....
public static decimal GetScoreForQuestion(int eventId, int ThingyQuestionId)
{
// the following line fails with the connection issue
var ThingyResults = Db.ThingyResults.Where(e => e.EventId == eventId && e.ThingyQuestionId == ThingyQuestionId)
.AsNoTracking().ToList();
:
:
:
}
Db is declared in the same class as...
public static class ReportingServices
{
private static readonly ThingyContext Db = new ThingyContext();
When you are executing a unittest, that project is your running application. So that is where the configuration file is read from. And note that you need an app.config, not a web.config.
It looks like you may be creating a new ThingyContext within your ReportingServices class. Look into injecting an Interface so that you can substitute a mock implementation for testing purposes.
Here's some links to help get you started:
https://romiller.com/2012/02/14/testing-with-a-fake-dbcontext/
https://ardalis.com/new-is-glue
So, I'm trying to create a sample where there are the following components/features:
A hangfire server OWIN self-hosted from a Windows Service
SignalR notifications when jobs are completed
Github Project
I can get the tasks queued and performed, but I'm having a hard time sorting out how to then notify the clients (all currently, just until I get it working well) of when the task/job is completed.
My current issue is that I want the SignalR hub to be located in the "core" library SampleCore, but I don't see how to "register it" when starting the webapp SampleWeb. One way I've gotten around that is to create a hub class NotificationHubProxy that inherits the actual hub and that works fine for simple stuff (sending messages from one client to all).
In NotifyTaskComplete, I believe I can get the hub context and then send the message like so:
private void NotifyTaskComplete(int taskId)
{
try
{
var hubContext = GlobalHost.ConnectionManager.GetHubContext<NotificationHub>();
if (hubContext != null)
{
hubContext.Clients.All.sendMessage(string.Format("Task {0} completed.", taskId));
}
}
catch (Exception ex)
{
}
}
BUT, I can't do that if NotificationHubProxy is the class being used as it's part of the SampleWeb library and referencing it from SampleCore would lead to a circular reference.
I know the major issue is the hub in the external assembly, but I can't for the life of me find a relevant sample that's using SignalR or MVC5 or setup in this particular way.
Any ideas?
So, the solution was to do the following two things:
I had to use the SignalR .NET client from the SampleCore assembly to create a HubConnection, to create a HubProxy to "NotificationHub" and use that to Invoke the "SendMessage" method - like so:
private void NotifyTaskComplete(string hostUrl, int taskId)
{
var hubConnection = new HubConnection(hostUrl);
var hub = hubConnection.CreateHubProxy("NotificationHub");
hubConnection.Start().Wait();
hub.Invoke("SendMessage", taskId.ToString()).Wait();
}
BUT, as part of creating that HubConnection - I needed to know the url to the OWIN instance. I decided to pass that a parameter to the task, retrieving it like:
private string GetHostAddress()
{
var request = this.HttpContext.Request;
return string.Format("{0}://{1}", request.Url.Scheme, request.Url.Authority);
}
The solution to having a Hub located in an external assembly is that the assembly needs to be loaded before the SignalR routing is setup, like so:
AppDomain.CurrentDomain.Load(typeof(SampleCore.NotificationHub).Assembly.FullName);
app.MapSignalR();
This solution for this part came from here.
is it possible to execute a server side program and get the output asynchronously.
i have this code that doing the job but synchronously:
suppose a c# program "program.exe" like this :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace testconsole
{
class Program
{
static void Main(string[] args)
{
for (int k = 0; k < 10; k++ )Console.WriteLine(k);
}
}
}
some view in the asp.net app like this :
<script >
function go()
{
var options = {
url: '/excute',
type: 'GET',
dataType: 'json'
}
//make call
$.ajax(options)
.then(function (data) {
console.log(data);
});
}
</script>
<input type="submit" onclick="go();" value="Go">
and the excute controller looks like this :
namespace myApp.Controllers
{
public class ExecuteController : Controller
{
//
// GET: /Execute
[HttpGet]
public JsonResult Index()
{
Process p = new Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.FileName = "program.exe";
p.Start();
string output = p.StandardOutput.ReadToEnd();
p.WaitForExit();
return Json(new { op = output }, JsonRequestBehavior.AllowGet);
}
}
}
All this is working fine, But ... from the client have to wait till the end of the program to display its outputs, is there any way to get those outputs as soon as they r created?
im sur i need to make some changes in the controller to make it possible, but how ???
Asp.Net MVC has the concept of an Async Controller that is suited to perform long-running tasks. It will help you by not locking a thread while you wait for out program to execute.
But to do what you are after I think you need to create you own Http Handler (probaby by implementing the IHttpHandler interface) that wraps the process and returns the results incrementally. This will not be trivial to do, but it should be possible.
A third viable alternative might be to use SignalR. That would be a fun project, but would still require much work I think.
The problem is primarily with communication between the IIS host process and your external process. You would need to facilitate some sort channel of communication to send "progress" events from the console application into the ASP.NET application.
A WCF client sending information via named pipes to a service hosted in the ASP.NET application would enable you to send messages into the application. You would host the service when the request is made and dynamically generate the name of pipe as a way to correlate to the initial request.
Once you get the updates in the application, you could then use something like SignalR to allow you to push the information back up the client.
Im back finally with an answer (not perfect i suppose). I used SignalR to get this done.
i created a messenger program (with c#) that will be the bridge between an asp.net mvc4 application and any console program that displays outputs.
the messenger will execute the program , then redirect his outputs to be send trough SignalR to the client.
if you are interested i've created a repo at github for this ,check this code here. I hope it will help someone one day.
i will be happy to talk about this code with you.