protected ExpressionStarter <ResCurrentType> PredicateSearchParameter < ResCurrentType, ResIndexStringType, ResIndexTokenType, ResIndexUriType, ResIndexReferenceType, ResIndexQuantityType, ResIndexDateTimeType>(SearchParameterBase SearchItem) where ResCurrentType : ResourceCurrentBase <ResCurrentType, ResIndexStringType, ResIndexTokenType, ResIndexUriType, ResIndexReferenceType, ResIndexQuantityType, ResIndexDateTimeType> where ResIndexStringType : ResourceIndexString <ResCurrentType, ResIndexStringType, ResIndexTokenType, ResIndexUriType, ResIndexReferenceType, ResIndexQuantityType, ResIndexDateTimeType> where ResIndexTokenType : ResourceIndexToken <ResCurrentType, ResIndexStringType, ResIndexTokenType, ResIndexUriType, ResIndexReferenceType, ResIndexQuantityType, ResIndexDateTimeType> where ResIndexUriType : ResourceIndexUri <ResCurrentType, ResIndexStringType, ResIndexTokenType, ResIndexUriType, ResIndexReferenceType, ResIndexQuantityType, ResIndexDateTimeType>, new() where ResIndexReferenceType : ResourceIndexReference <ResCurrentType, ResIndexStringType, ResIndexTokenType, ResIndexUriType, ResIndexReferenceType, ResIndexQuantityType, ResIndexDateTimeType> where ResIndexQuantityType : ResourceIndexQuantity <ResCurrentType, ResIndexStringType, ResIndexTokenType, ResIndexUriType, ResIndexReferenceType, ResIndexQuantityType, ResIndexDateTimeType> where ResIndexDateTimeType : ResourceIndexDateTime <ResCurrentType, ResIndexStringType, ResIndexTokenType, ResIndexUriType, ResIndexReferenceType, ResIndexQuantityType, ResIndexDateTimeType> { var Search = new ResourceSearch <ResCurrentType, ResIndexStringType, ResIndexTokenType, ResIndexUriType, ResIndexReferenceType, ResIndexQuantityType, ResIndexDateTimeType>(); ExpressionStarter <ResCurrentType> Predicate = LinqKit.PredicateBuilder.New <ResCurrentType>(); switch (SearchItem.Type) { case SearchParamType.Date: Predicate = DateTimePeriodPredicateBuilder <ResCurrentType, ResIndexStringType, ResIndexTokenType, ResIndexUriType, ResIndexReferenceType, ResIndexQuantityType, ResIndexDateTimeType> .Build(Search, Predicate, SearchItem); break; case SearchParamType.Number: { if (SearchItem is SearchParameterNumber) { var SearchTypeNumber = SearchItem as SearchParameterNumber; foreach (var SearchValue in SearchTypeNumber.ValueList) { if (SearchTypeNumber.Name != "page") { //ToDo: more needed here } } } Predicate = NumberPredicateBuilder <ResCurrentType, ResIndexStringType, ResIndexTokenType, ResIndexUriType, ResIndexReferenceType, ResIndexQuantityType, ResIndexDateTimeType> .Build(Search, Predicate, SearchItem); } break; case SearchParamType.Quantity: Predicate = QuantityPredicateBuilder <ResCurrentType, ResIndexStringType, ResIndexTokenType, ResIndexUriType, ResIndexReferenceType, ResIndexQuantityType, ResIndexDateTimeType> .Build(Search, Predicate, SearchItem); break; case SearchParamType.Reference: Predicate = ReferancePredicateBuilder <ResCurrentType, ResIndexStringType, ResIndexTokenType, ResIndexUriType, ResIndexReferenceType, ResIndexQuantityType, ResIndexDateTimeType> .Build(Search, Predicate, SearchItem, IPrimaryServiceRootCache.GetPrimaryRootUrlFromDatabase()); break; case SearchParamType.String: Predicate = StringPredicateBuilder <ResCurrentType, ResIndexStringType, ResIndexTokenType, ResIndexUriType, ResIndexReferenceType, ResIndexQuantityType, ResIndexDateTimeType> .Build(Search, Predicate, SearchItem); break; case SearchParamType.Token: Predicate = TokenPredicateBuilder <ResCurrentType, ResIndexStringType, ResIndexTokenType, ResIndexUriType, ResIndexReferenceType, ResIndexQuantityType, ResIndexDateTimeType> .Build(Search, Predicate, SearchItem); break; case SearchParamType.Uri: Predicate = UriPredicateBuilder <ResCurrentType, ResIndexStringType, ResIndexTokenType, ResIndexUriType, ResIndexReferenceType, ResIndexQuantityType, ResIndexDateTimeType> .Build(Search, Predicate, SearchItem); break; default: throw new System.ComponentModel.InvalidEnumArgumentException(SearchItem.Type.ToString(), (int)SearchItem.Type, typeof(SearchParamType)); } return(Predicate); }
public IResourceServiceOutcome GetServersConformanceResource(IRequestMeta RequestMeta) { if (RequestMeta == null) { throw new NullReferenceException("RequestMeta can not be null."); } if (RequestMeta.SearchParameterGeneric == null) { throw new NullReferenceException("SearchParameterGeneric can not be null."); } IResourceServiceOutcome ServiceOperationOutcome = IResourceServiceOutcomeFactory.CreateResourceServiceOutcome(); ISearchParameterService SearchService = ISearchParameterServiceFactory.CreateSearchParameterService(); ISearchParametersServiceOutcome SearchParametersServiceOutcome = SearchService.ProcessBaseSearchParameters(RequestMeta.SearchParameterGeneric); if (SearchParametersServiceOutcome.FhirOperationOutcome != null) { ServiceOperationOutcome.ResourceResult = SearchParametersServiceOutcome.FhirOperationOutcome; ServiceOperationOutcome.HttpStatusCode = SearchParametersServiceOutcome.HttpStatusCode; ServiceOperationOutcome.FormatMimeType = SearchParametersServiceOutcome.SearchParameters.Format; return(ServiceOperationOutcome); } var Conformance = new CapabilityStatement(); var ApplicationReleaseDate = new DateTimeOffset(2017, 10, 17, 6, 00, 00, new TimeSpan(8, 0, 0)); string ServerName = "Pyro Server"; string Https = "https://"; Conformance.Id = "metadata"; Conformance.Url = $"{Https}{IPrimaryServiceRootCache.GetPrimaryRootUrlFromDatabase().Url}/metadata"; Conformance.Version = $"V{IGlobalProperties.ApplicationVersionInfo}"; Conformance.Meta = new Meta(); Conformance.Meta.LastUpdated = ApplicationReleaseDate; Conformance.Name = ServerName; Conformance.Status = PublicationStatus.Active; Conformance.Experimental = true; Conformance.Date = (new FhirDateTime(ApplicationReleaseDate)).Value; Conformance.Publisher = "PyroHealth.net"; var AngusContactDetail = Common.PyroHealthInformation.PyroHealthContactDetailAngusMillar.GetContactDetail(); Conformance.Contact = new List <ContactDetail>() { AngusContactDetail }; Conformance.Description = new Markdown("Conformance statement for the " + ServerName); var Australia = new CodeableConcept("urn:iso:std:iso:3166", "AU", "Australia"); Conformance.Jurisdiction = new List <CodeableConcept>() { Australia }; Conformance.Purpose = new Markdown("FHIR Server reference implementation"); Conformance.Copyright = new Markdown("Copyright: PyroHealth.net"); Conformance.Kind = CapabilityStatement.CapabilityStatementKind.Instance; Conformance.Software = new CapabilityStatement.SoftwareComponent(); Conformance.Software.Name = ServerName; Conformance.Software.Version = IGlobalProperties.ApplicationVersionInfo; //To align with FHIR version only use number no prefix of 'V' Conformance.Software.ReleaseDate = (new FhirDateTime(ApplicationReleaseDate)).Value; Conformance.Implementation = new CapabilityStatement.ImplementationComponent(); Conformance.Implementation.Description = $"{ServerName} is an implementation of a FHIR server supporting V{Hl7.Fhir.Model.ModelInfo.Version} of the specification. This instance is a publicly available testing server and its resource may be cleared at any time."; Conformance.Implementation.Url = $"{Https}{IPrimaryServiceRootCache.GetPrimaryRootUrlFromDatabase().Url}"; Conformance.FhirVersion = Hl7.Fhir.Model.ModelInfo.Version; //Must be formated as just the number '3.0.1' as touchstone does not like the V3.0.1 Conformance.AcceptUnknown = CapabilityStatement.UnknownContentCode.Extensions; var ContentFormatList = new List <string>(); foreach (var mediaType in Hl7.Fhir.Rest.ContentType.XML_CONTENT_HEADERS) { ContentFormatList.Add(mediaType); } foreach (var mediaType in Hl7.Fhir.Rest.ContentType.JSON_CONTENT_HEADERS) { ContentFormatList.Add(mediaType); } Conformance.Format = ContentFormatList; Conformance.Rest = new List <CapabilityStatement.RestComponent>(); var RestComponent = new CapabilityStatement.RestComponent(); Conformance.Rest.Add(RestComponent); RestComponent.Mode = CapabilityStatement.RestfulCapabilityMode.Server; RestComponent.Documentation = $"STU{Hl7.Fhir.Model.ModelInfo.Version.Split('.')[0]} V{Hl7.Fhir.Model.ModelInfo.Version} FHIR Server"; RestComponent.Security = new CapabilityStatement.SecurityComponent(); RestComponent.Security.Description = "No Security has been implemented, server if publicly open"; RestComponent.Interaction = new List <CapabilityStatement.SystemInteractionComponent>(); var SystemInteractionComponent = new CapabilityStatement.SystemInteractionComponent(); RestComponent.Interaction.Add(SystemInteractionComponent); SystemInteractionComponent.Code = CapabilityStatement.SystemRestfulInteraction.Transaction; SystemInteractionComponent.Documentation = "Batch Transaction supports all request methods (Delete, POST, PUT, GET) including conditional create/update/delete. Operatons are not supported within Transaction bundles."; var CompartmentList = IServiceCompartmentRepository.GetAllServiceCompartments(); if (CompartmentList != null && CompartmentList.Count > 0) { var CompartmentUrlList = new List <string>(); CompartmentList.ForEach(x => CompartmentUrlList.Add(x.Url)); RestComponent.Compartment = CompartmentUrlList; } RestComponent.Resource = new List <CapabilityStatement.ResourceComponent>(); List <DtoServiceSearchParameterHeavy> DtoServiceSearchParameterHeavyList = IServiceSearchParameterService.GetServiceSearchParametersHeavy(false); var ResourceTypeList = Enum.GetValues(typeof(ResourceType)); foreach (ResourceType ResourceType in ResourceTypeList) { string CurrentResourceString = ResourceType.GetLiteral(); FHIRAllTypes?FhirType = Hl7.Fhir.Model.ModelInfo.FhirTypeNameToFhirType(CurrentResourceString); var ResourceComponent = new CapabilityStatement.ResourceComponent(); RestComponent.Resource.Add(ResourceComponent); ResourceComponent.Type = ResourceType; ResourceComponent.Interaction = new List <CapabilityStatement.ResourceInteractionComponent>() { new CapabilityStatement.ResourceInteractionComponent() { Code = CapabilityStatement.TypeRestfulInteraction.Create }, new CapabilityStatement.ResourceInteractionComponent() { Code = CapabilityStatement.TypeRestfulInteraction.Delete }, new CapabilityStatement.ResourceInteractionComponent() { Code = CapabilityStatement.TypeRestfulInteraction.Read }, new CapabilityStatement.ResourceInteractionComponent() { Code = CapabilityStatement.TypeRestfulInteraction.Update }, new CapabilityStatement.ResourceInteractionComponent() { Code = CapabilityStatement.TypeRestfulInteraction.Vread }, new CapabilityStatement.ResourceInteractionComponent() { Code = CapabilityStatement.TypeRestfulInteraction.SearchType }, new CapabilityStatement.ResourceInteractionComponent() { Code = CapabilityStatement.TypeRestfulInteraction.HistoryInstance }, new CapabilityStatement.ResourceInteractionComponent() { Code = CapabilityStatement.TypeRestfulInteraction.HistoryType } //new Conformance.ResourceInteractionComponent() { Code = Conformance.TypeRestfulInteraction.HistoryType}, }; ResourceComponent.Versioning = CapabilityStatement.ResourceVersionPolicy.Versioned; ResourceComponent.ReadHistory = true; ResourceComponent.UpdateCreate = true; ResourceComponent.ConditionalCreate = true; ResourceComponent.ConditionalRead = CapabilityStatement.ConditionalReadStatus.FullSupport; ResourceComponent.ConditionalUpdate = true; ResourceComponent.ConditionalDelete = CapabilityStatement.ConditionalDeleteStatus.Multiple; var ReferenceHandlingPolicyList = new List <CapabilityStatement.ReferenceHandlingPolicy?>(); ReferenceHandlingPolicyList.Add(CapabilityStatement.ReferenceHandlingPolicy.Literal); ReferenceHandlingPolicyList.Add(CapabilityStatement.ReferenceHandlingPolicy.Local); ResourceComponent.ReferencePolicy = ReferenceHandlingPolicyList; List <DtoServiceSearchParameterHeavy> DtoServiceSearchParameterHeavyForResourceList = DtoServiceSearchParameterHeavyList.Where(x => x.Resource == CurrentResourceString || x.Resource == FHIRAllTypes.Resource.GetLiteral()).ToList(); //List<ServiceSearchParameterHeavy> DtoServiceSearchParameterHeavyForResourceList = ICommonServices.GetServiceSearchParametersHeavyForResource(FhirType.Value.GetLiteral()); //DtoServiceSearchParameterHeavyForResourceList.AddRange(ICommonServices.GetServiceSearchParametersHeavyForResource(FHIRAllTypes.Resource.GetLiteral())); ResourceComponent.SearchParam = new List <CapabilityStatement.SearchParamComponent>(); List <string> IncludesList = null; List <string> RevIncludesList = null; foreach (var SupportedSearchParam in DtoServiceSearchParameterHeavyForResourceList) { if (SupportedSearchParam.IsIndexed && SupportedSearchParam.Status == PublicationStatus.Active) { //Include (RevIncludes are below) if (SupportedSearchParam.Type == SearchParamType.Reference) { if (IncludesList == null) { IncludesList = new List <string>(); } if (SupportedSearchParam.TargetResourceTypeList.Count > 1) { foreach (var Target in SupportedSearchParam.TargetResourceTypeList) { IncludesList.Add($"{SupportedSearchParam.Resource}:{SupportedSearchParam.Name}:{Target.ResourceType.GetLiteral()}"); } } else { IncludesList.Add($"{SupportedSearchParam.Resource}:{SupportedSearchParam.Name}"); } } CapabilityStatement.SearchParamComponent SearchParamComponent = new CapabilityStatement.SearchParamComponent(); ResourceComponent.SearchParam.Add(SearchParamComponent); SearchParamComponent.Name = SupportedSearchParam.Name; SearchParamComponent.Type = SupportedSearchParam.Type; SearchParamComponent.Definition = SupportedSearchParam.Url; if (!string.IsNullOrWhiteSpace(SupportedSearchParam.Description)) { SearchParamComponent.Documentation = SupportedSearchParam.Description; } } } ResourceComponent.SearchInclude = IncludesList; //RevIncludes var RevIncludeSearchParameterList = DtoServiceSearchParameterHeavyList.Where(x => x.Type == SearchParamType.Reference && x.TargetResourceTypeList.Any(c => c.ResourceType == ResourceType)); foreach (var Rev in RevIncludeSearchParameterList) { if (RevIncludesList == null) { RevIncludesList = new List <string>(); } if (Rev.TargetResourceTypeList.Count > 1) { RevIncludesList.Add($"{Rev.Resource}:{Rev.Name}:{CurrentResourceString}"); } else { RevIncludesList.Add($"{Rev.Resource}:{Rev.Name}"); } } ResourceComponent.SearchRevInclude = RevIncludesList; } ConstructConformanceResourceNarrative(Conformance); IDatabaseOperationOutcome DatabaseOperationOutcome = IDatabaseOperationOutcomeFactory.CreateDatabaseOperationOutcome(); ServiceOperationOutcome.FhirResourceId = Conformance.Id; ServiceOperationOutcome.ResourceVersionNumber = Conformance.Version; ServiceOperationOutcome.LastModified = Conformance.Meta.LastUpdated; ServiceOperationOutcome.OperationType = Common.Enum.RestEnum.CrudOperationType.Read; ServiceOperationOutcome.IsDeleted = false; ServiceOperationOutcome.RequestUri = null; ServiceOperationOutcome.ResourceResult = Conformance; ServiceOperationOutcome.FormatMimeType = SearchParametersServiceOutcome.SearchParameters.Format; ServiceOperationOutcome.HttpStatusCode = System.Net.HttpStatusCode.OK; return(ServiceOperationOutcome); }
public IDtoRootUrlStore Validate(string RequestServiceRoot) { string RequestRoot = RequestServiceRoot.ToLower(); string ErrorMsg = "Error message not set in PrimaryServiceRootFactory"; string WebConfigServiceBase = IPrimaryServiceRootCache.GetPrimaryRootUrlFromWebConfig().ToLower(); IDtoRootUrlStore IDtoPrimaryRootUrlStore = IPrimaryServiceRootCache.GetPrimaryRootUrlFromDatabase(); if (IDtoPrimaryRootUrlStore != null && RequestRoot.IsEqualUri(IDtoPrimaryRootUrlStore.Url) && RequestRoot.IsEqualUri(WebConfigServiceBase)) { //All checks a good return return(IDtoPrimaryRootUrlStore); } if (IDtoPrimaryRootUrlStore == null && RequestRoot.IsEqualUri(WebConfigServiceBase)) { //Clean install. //There is no primary in the database / Cache. //If the Web.Config ServiceBaseURL equals the incoming request Service Base URL //Therefore set the database's primary service root URL, as this is a clean install. ILog.Info($"Clean install detected. As the first request's Service root is equal to the ServiceBaseURL found in the App_Data\\PyroApp.config this will be set in the database for future requests. ServiceBaseURL is : {IPrimaryServiceRootCache.GetPrimaryRootUrlFromWebConfig()} "); IDtoRootUrlStore DtoRootUrlStore = IServicePrimaryBaseUrlService.SetPrimaryRootUrlStore(WebConfigServiceBase.StripHttp().ToLower()); //Clear the cache as we just added the ServiceRoot to the database as the cache will have null cached. IPrimaryServiceRootCache.ClearPrimaryRootUrlFromCache(); return(DtoRootUrlStore); } if (IDtoPrimaryRootUrlStore != null && RequestRoot.IsEqualUri(WebConfigServiceBase) && !RequestRoot.IsEqualUri(IDtoPrimaryRootUrlStore.Url)) { //Web.Config Changed //The incoming request Service Base URL equals the Web.Config entry yet does not equal the Service Base URL //found in the database. We will assume someone knows what they are doing if they are capable of changing the Web.Config setting. //So update the database primary Service Base URL to match the Web.Config and request ILog.Info($"The incoming request's Service Base URL equals the App_Data\\PyroApp.config file entry 'ServiceBaseURL' yet does not equal the Primary Service Base URL found in the database. The server will assume someone knows what they are doing if they are capable of changing the App_Data\\PyroApp.config setting and will update the database primary Service Base URL to match the App_Data\\PyroApp.config and request. "); //Clear the cache as we just added the ServiceRoot to the database as the cache will have null cached. IPrimaryServiceRootCache.ClearPrimaryRootUrlFromCache(); IDtoRootUrlStore DtoRootUrlStore = IServicePrimaryBaseUrlService.SetPrimaryRootUrlStore(WebConfigServiceBase.StripHttp().ToLower()); return(DtoRootUrlStore); } if (IDtoPrimaryRootUrlStore == null && !RequestRoot.IsEqualUri(WebConfigServiceBase)) { //Clean Install yet request does not match Web.Config file //There is no primary in the database / Cache and the incoming request Service Base URL //does not match that in the Web.Config file. //This is a configuration error. ErrorMsg = "The ServiceBaseURL configured in the Servers Web.Config does not match the service root URL found in the incoming request."; throw new PyroException(System.Net.HttpStatusCode.InternalServerError, Common.Tools.FhirOperationOutcomeSupport.Create(OperationOutcome.IssueSeverity.Fatal, OperationOutcome.IssueType.Exception, ErrorMsg), ErrorMsg); } if (IDtoPrimaryRootUrlStore != null && (!RequestRoot.IsEqualUri(WebConfigServiceBase) || !RequestRoot.IsEqualUri(IDtoPrimaryRootUrlStore.Url))) { //Existing server moved and Web.Config file not updated to match the move. //The incoming request Service Base URL does not equal the Web.Config entry or the Database //Warn the user about the ramifications of this change if they should seek to make the change to the Web.Config file ErrorMsg = $"The incoming Http request had a service root URL of: '{RequestServiceRoot.StripHttp()}'. " + $"The server's database service root URL was '{IDtoPrimaryRootUrlStore.Url}'. " + $"The servers PyroApp.config file service root URL was '{WebConfigServiceBase.StripHttp()}'. " + "All three URLs must match for the server to continue! " + "This is most likely due to the server being move from it's original URL location, or the PyroApp.config value being incorrect. " + "You need to consider carefully the ramifications of or actions. you take next. " + "External systems may have absolute references to FHIR resources in this server " + "and changing the primary service root URL may render these external references invalid. " + "What can you do?. In the servers App_Data\\PyroApp.config appSetttings is a Key names 'ServiceBaseURL'. You can update this to " + $"the new service root URL in use. If you change this to equal '{RequestServiceRoot}' the server " + "will use this going forward as the service root URL for new resource. Yet all absolute references outside the database " + "will become invalid. " + "This change is not to be taken lightly and you should consider the ramifications carefully in the context of the " + "systems that interact with this service. "; throw new PyroException(System.Net.HttpStatusCode.InternalServerError, Common.Tools.FhirOperationOutcomeSupport.Create(OperationOutcome.IssueSeverity.Fatal, OperationOutcome.IssueType.Exception, ErrorMsg), ErrorMsg); } ErrorMsg = "Server Internal Error: Logic to resolve the Primary Service Root has failed. "; throw new PyroException(System.Net.HttpStatusCode.InternalServerError, Common.Tools.FhirOperationOutcomeSupport.Create(OperationOutcome.IssueSeverity.Fatal, OperationOutcome.IssueType.Exception, ErrorMsg), ErrorMsg); }