22

Nov

.NET e CicsWebServices

Ciao a tutti

 

Alcune volte, particolarmente se si lavora in banca, in assicurazioni o grandi società con software legacy è necessario invocare alcune applicazioni su questi sistemi.

Per quanto riguarda la necessità di connettere il .NET con CICS che gira su un Mainframe IBM è possibile utilizzare il driver HIS di BizTalk Server così da invocare da remoto alcuni di questi programmi in un contesto transazionale, ed esporre eventualmente queste operazioni tramite workflow d’integrazione o come webservice da parte dello stesso BizTalk. Alternativamente è possibile realizzare dei programmi in EGL (enterprise generation language) un linguaggio ad oggetti della IBM in grado di generare a sua volta programmi COBOL o JAVA, esposti all’esterno come dei WebServices SOAP dallo stesso CICS. In pratica un Mainframe SOA.

 

image

 

Dai test che ho potuto fare con alcuni colleghi dedicati alla parte EGL sembra che l’esposizione di alcuni programmi come WebServices nel CICS sia 1 procedura rognosa. Quindi non siamo riusciti a testarla in maniera funzionante. Spero di tornare sull’argomento quando potrò rimettere le mani sul mainframe.

 

Differentemente il test per far si che un programma CICS opportunamente modificato o realizzato richiami un web service siamo riusciti a farlo, ad oggi con questi risultati:

Da CICS a JAVA AXIS2, WebService WS-I Basic, document style. Funzionante sia nel passaggio i 1 parametro complesso che nella ricezione.

Da CICS a .NET WebService (asmx), WS-I Basic, RPC-style, Funzionante con request e response primitivi (intero, stringa). Il test con un oggetto in request e in response è stato correttamente letto dal generatore del proxy client, ma l’invoke ha generato una abend (abnormal end). Il mio dubbio sta nel settaggio della formattazione dello stile dei parametri (es. bare o wrapped) nel senso che potrebbero non collimare tra  come li ha serializzati il cics e come li aspettava l’asmx provocando una request con parametri a null che poi ovviamente spaccavano il servizio nella stupida logica che esponeva.

Un test con document style è in attesa di essere fatto… credo non ci siano problemi visto l’esito con JAVA.

Da CICS a WCF con basicHttp non ha funzionato per il wsdl che genera WCF di default. nel senso che EGL on riesce nemmeno a generare il proxy client. Credo comunque che la seguente configurazione funzioni, ma devo aspettare per darvi 1 conferma:

[MessageContract]
public class SimpleRequest
{
    [MessageBodyMember]
    public string Value { get; set; }
}

[DataContract]
public class ResponseObject
{
    [DataMember]
    public string Value { get; set; }
}

[MessageContract]
public class SimpleResponse
{
    [MessageBodyMember]
    public ResponseObject Value { get; set; }
}

[ServiceContract(Namespace = "http://stessonamespace.simple.service.it")]
public interface ISimpleService
{
    [OperationContract]
    SimpleResponse Invoke(SimpleRequest request);
}

[ServiceBehavior(Namespace = "http://stessonamespace.simple.service.it")]
public class SimpleServiceHandler : ISimpleService
{
    public SimpleResponse Invoke(SimpleRequest request)
    {
        return new SimpleResponse() { Value = new ResponseObject() { Value = request.Value } };
    }
}

il .config invece:


 
   
     
       
     

   

 

 
   
     
       
          http://localhost:9090/SimpleService.svc"/>
       

     

     
                      address="" binding="basicHttpBinding" contract="ISimpleService"
                bindingNamespace="
http://stessonamespace.simple.service.it"/>
   

 

 

è importante che il namespace del contratto e dell’handler siano uguali altrimenti il WSDL verrà generato in maniera sbagliata.

poi è importante impostare il nome dell’endpoint perchè verrà considerato il nome della porta nel WSDL, nome che sul nostro CICS con le nostre configurazione non può essere superiore a 30 caratteri (mah).

è importante anche impostare lo stesso namespace nel bindingNamespace dell’endpoint altrimenti il generatore del WSDN non genererà correttamente i dati di binding cosa che renderà impossibile la generazione del proxy client in EGL.

infine è necessario flatterizzare il WSDL generato dal WCF che utilizza degli include verso degli XSD per i vari messaggi e tipi che transitano, oltre alle informazioni di serializzazione/deserializzazione. per farlo è possibile utilizzare questo codice di thinktecture:

 

using System.Collections;
      using System.Collections.Generic;
      using System.ServiceModel.Channels;
      using System.ServiceModel.Description;
      using System.ServiceModel.Dispatcher;
      using System.Xml.Schema;
      using System.ServiceModel.Configuration;
      using ServiceDescription = System.Web.Services.Description.ServiceDescription;

      namespace Thinktecture.ServiceModel.Extensions.Description
      {
      public class FlatWsdl : BehaviorExtensionElement,IWsdlExportExtension, IEndpointBehavior
      {
      public void ExportContract(WsdlExporter exporter, WsdlContractConversionContext context)
      {
      }

      public void ExportEndpoint(WsdlExporter exporter, WsdlEndpointConversionContext context)
      {
      XmlSchemaSet schemaSet = exporter.GeneratedXmlSchemas;

      foreach (ServiceDescription wsdl in exporter.GeneratedWsdlDocuments)
      {
      List importsList = new List();

      foreach (XmlSchema schema in wsdl.Types.Schemas)
      {
      AddImportedSchemas(schema, schemaSet, importsList);
      }

      wsdl.Types.Schemas.Clear();

      foreach (XmlSchema schema in importsList)
      {
      RemoveXsdImports(schema);
      wsdl.Types.Schemas.Add(schema);
      }
      }
      }

      private void AddImportedSchemas(XmlSchema schema, XmlSchemaSet schemaSet, List importsList)
      {
      foreach (XmlSchemaImport import in schema.Includes)
      {
      ICollection realSchemas =
      schemaSet.Schemas(import.Namespace);

      foreach (XmlSchema ixsd in realSchemas)
      {
      if (!importsList.Contains(ixsd))
      {
      importsList.Add(ixsd);
      AddImportedSchemas(ixsd, schemaSet, importsList);
      }
      }
      }
      }

      private void RemoveXsdImports(XmlSchema schema)
      {
      for (int i = 0; i < schema.Includes.Count; i++)
      {
      if (schema.Includes[i] is XmlSchemaImport)
      schema.Includes.RemoveAt(i--);
      }
      }

      public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
      {
      }

      public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
      {
      }

      public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
      {
      }

      public void Validate(ServiceEndpoint endpoint)
      {
      }

      public override System.Type BehaviorType
      {
      get { return typeof(FlatWsdl); }
      }

      protected override object CreateBehavior()
      {
      return new FlatWsdl();
      }
      }
      }
che va a creare un behaviorExtension che andremo a collegare al nostro servizio tramite il .config così: 


 
   
     
       
     

   

   
     
       
     

   

 

 
   
     
       
          http://localhost:9090/SimpleService.svc"/>
       

     

     
                      bindingNamespace="http://stessonamespace.simple.service.it"
                behaviorConfiguration="inline"
                />
   

 

 
   
     
   

 

 

alla fine dovrebbe funzionare correttamente Sorriso vi terrò informati sui miei progressi con i CicsWebServices

Antonio

by Antonio Esposito on 11/22/2010