Windward DocumentationWindward Core.NET RESTful Engine User Manual ReferenceExternal Storage Plugin for the .NET RESTful Engine

External Storage Plugin for the .NET RESTful Engine

The RESTful Engine is designed to use the computer's file system as a repository for all the files produced during the report generation process. If, however, you require something different for your setup, say using an AWS S3 bucket to store all the files, we provide the IRepository interface. This article will detail how to get started with the IRepository interface, as well as provide details surrounding the methods defined in the interface.

Note: If you are using VMs or containers with a load balancer, we recommend you set up a repository for object storage services like AWS S3 or Azure Storage.

What You Need

In order to implement your own repository, you will need:

  • WindwardRepository.dll
  • WindwardModels.dll

Please reach out to our support team for a the files listed above.

Setting It Up

  1. Acquire the WindwardRepository.dll and WindwardModels.dll files from our support team.
  2. Once you have the two dlls listed above, create a new C# project and add the dlls to the project dependencies. Then include the libraries to your class file, and define a class that implements IRepository:
    using WindwardRepository;
    using WindwardModels;
    namespace CustomRepo
    {    
       public class Repository : IRepository
       .
       .
       .
  3.  You will then need to implement the following repository methods (for more information about these methods please read the "Methods and Variables" section of this article):
    1. public void SetJobHandler(IJobHandler handler)
      1.  The SetJobHandler method sets the job handler for the RESTful engine. 
    2. public string CreateRequest(Template template, RepositoryStatus.REQUEST_TYPE requestType)
      1. The CreateRequest method is used to add report processing requests to the processing queue
    3. public void SaveError(Template template, ServiceError error)
      1.  The SaveError method saves an error that occurred during execution of a template.
    4. public ServiceError GetError(string guid)
      1.  The GetError method is used to retrieve an error associated with a specific request. 
    5.  public void SaveReport(Template template, Document document)
      1.  The SaveReport method saves a completed document generation request.
    6. public Document GetReport(string guid)
      1.  The GetReport method retrieves the document object associated with the passed GUID. 
    7. public RepositoryRequest TakeRequest() 
      1.  The TakeRequest method gets the pending jobs and sets them to processing.
    8. RequestStatus GetReportStatus(string guid)
      1.  The GetReportStatus method returns the status of the current request associated with the passed GUID.
    9. public DocumentMeta GetReportMeta(string guid)
      1.  The GetReportMeta method retrieves the documentMeta object associated with the passed GUID.
    10. public void SaveMetrics(Template template, Metrics metrics)
      1.  The SaveMetrics method saves a completed metrics request. 
    11. public Metrics GetMetrics(string guid)
      1.  The GetMetrics method retrieves the metrics object associated with the passed GUID. 
    12. public void SaveTagTree(Template template, TagTree tagtree)
      1.  The SaveTagTree method saves a completed tagtree request
    13. public Metrics GetTagTree(string guid) 
      1. The GetTagTree method retrieves the tagtree object associated with the passed GUID.
    14. public void DeleteReport(string guid)
      1.  The DeleteReport method is used to delete a generated document from the repository using its guid as the identifier.
    15. public void ShutDown()
      1.  The Shutdown method reverts all jobs in processing to pending (waiting to start). The web server is closing down.
  4.  Once you implement those methods in your repository project, compile it down to a dll
  5.  Reference the dll in your RESTful engine's web.config
    1. To see how to do that, check out the "How to Use Defined Repository" section of this article


Methods and Variables

This is a list of the variables and methods you will need to implement your version of IRepository. 

Please note that the code snippets provided for some of the methods bellow are only provided as an aid / guide for you as you define your repository. Feel free to use any variable or helper methods you need to achieve what you need to achieve.

SetJobHandler Method

Method definition:

public void SetJobHandler(IJobHandler handler)

Input parameters:

  1. IJobHandler handler
    1. The job handler that will process requests in this repository

The SetJobHandler method sets the job handler for the RESTful engine. You should define the following variable in your repository class:

private IJobHandler JobHandler { get; set; }

For this method this is all you will need to do:

public void SetJobHandler(IJobHandler handler){
   JobHandler = handler;        
}

CreateRequest Method

Method definition:

public string CreateRequest(Template template, RepositoryStatus.REQUEST_TYPE requestType)

Input parameters:

  1. Template template
    1. The template that requires processing
  2. RepositoryStatus.REQUEST_TYPE requestType
    1.  What type of processing does this template need (ex. document, metrics, tagtree)

The CreateRequest method is used to add processing requests to the processing queue. In here you want to assign the template a GUID as so:

template.Guid = Guid.NewGuid().ToString();

If you are using our provided job handler, we recommend you setup a requests queue, and use it as follows:

private ConcurrentQueue<Tuple<Template, RepositoryStatus.REQUEST_TYPE>> queueRequests;
private AutoResetEvent eventSignal;
.
.
.

public string CreateRequest(Template template, RepositoryStatus.REQUEST_TYPE requestType) {
   .
   .
   .
   template.Guid = Guid.NewGuid().ToString();                  
   queueRequests.Enqueue(new Tuple<Template, RepositoryStatus.REQUEST_TYPE>(template, requestType));               
   eventSignal.Set();                
   return template.Guid;


Note that you have access to all the models used in these methods (like ServiceError, Template, Document, etc.) For a full list of the models, check our swagger documentation. You can use these to serialize / deserialize objects, especially when it comes to the Save/Get methods bellow.

SaveError Method

Method definition:

public void SaveError(Template template, ServiceError error)

Input parameters:

  1.  Template template
    1.  The template that failed during processing
  2. ServiceError error
    1.  An exception that occured attempting to execute a request.


The SaveError method saves an error that occurred during execution of a template. You can do this however you want; you can save it as an entry in your database, you can save it as a file, whatever works for you. As an example, the default FileSystemRepository implemented in the RESTful engine serializes the errors as data contracts to files titled {template.guid}.error. Just make sure however you save it, you use the template's guid as an identifier (name of the file, id entry in database, etc.).

GetError Method

Method definition:

public ServiceError GetError(string guid)

Input parameters:

  1.  guid
    1. The unique identifier for this request.

The GetError method is used to retrieve an error associated with a specific request. Use the guid input parameter as an identifier to find the error however you chose to save it in the SaveError method.

SaveReport Method

Method definition:

public void SaveReport(Template template, Document document)

Input parameters:

  1.  Template template
    1.  The template associated with this request.
  2. Document document
    1.  The generated report.

The SaveReport method saves a completed document generation request. You can save the document object however you want, as long as it is easily identifiable using its GUID. As an example, the default FileSystemRepository implemented in the RESTful engine serializes the errors as data contracts to files titled  " {template.guid}.docGen.complete".  Just make sure however you save it, you use the template's guid as an identifier (name of the file, id entry in database, etc.).

GetReport Method

Method definition:

public Document GetReport(string guid)

Input parameters:

  1.  guid
    1. The unique identifier for this request.

The GetReport method retrieves the document object associated with the passed GUID. Use the GUID input parameter as an identifier to find the document object however you chose to save it in the SaveReport method.

TakeRequest Method

Method definition:

RepositoryRequest TakeRequest()


The TakeRequest method gets pending jobs and sets them to processing (we save pending jobs with ".pending" extension and change it to ".generating" extension. You then want to return a RepositoryRequest object. These are the two constructors you can use for RepositoryRequest:

public RepositoryRequest(Template template, REQUEST_TYPE type) {
    this.Template = template;
    this.Type = type;
}

public RepositoryRequest(RepositoryRequest src) {
    this.Template = src.getTemplate();
    this.Type = src.getType();
}

These are the possible REQUEST_TYPE depending on the job:

public static enum REQUEST_TYPE {
    Unknown,
    DocGen,
    DocStream,
    DocGenMeta,
    Metrics,
    TagTree;

If there are no pending jobs, this method returns null.

GetRequestStatus Method

Method definition:

public RequestStatus GetReportStatus(string guid)

Input parameters:

  1.  guid
    1. The unique identifier for this request.

The GetReportStatus method returns the status of a job (identified by its GUID). This method returns a RequestStatus object:

public RequestStatus(RepositoryStatus.JOB_STATUS jobStatus, RepositoryStatus.REQUEST_TYPE requestType)        
{            
   JobStatus = jobStatus;            
   RequestType = requestType;        
}

Where JobStatus is an enum:

public enum JOB_STATUS        
{             
   Lock, ( A lock file ie. not really a job)
   Pending, (Waiting to run)
   Generating, (Presently running.)
   Complete, (Request is complete, successful)
   Error (Request had an error. Complete but failed)       
}

and RequestType is an enum:

public enum REQUEST_TYPE        
{ 
   Unknown, (Should only be set for JOB_STATUS == Error)
   DocGen, (Generating a document)
   DocStream, (Retrieve generated report as a stream)
   DocGenMeta, (Retrieve document "meta" data)
   Metrics, (Calling GetMetrics)
   TagTree  (Calling GetTagTree)      
}

As an example, the way we have it setup, when a document generation job is complete it will save the file with the following extention: "docgen.complete". So when we call the GetReportStatus method on this job, it will return the following RequestStatus object:

new RequestStatus(RepositoryStatus.JOB_STATUS.Complete,   RepositoryStatus.REQUEST_TYPE.DocGen)

GetReportMeta

Method definition:

public DocumentMeta GetReportMeta(string guid)

Input parameters:

  1.  guid
    1. The unique identifier for this request.

The GetReportMeta method retrieves the documentMeta object associated with the passed GUID. This method works slightly differently than other methods, as it basically make use of the already existing document object, and strips the necessary information from it. For this method we recommend you implement it like we did (with the associated helper method) or at least implement something with similar functionality:


public DocumentMeta GetReportMeta(string guid){
   Document document = GetReport(guid);
   DocumentMeta documentMeta = SetReportMeta(document);
   return documentMeta;
}

internal static DocumentMeta SetReportMeta(Document genDoc){
   DocumentMeta largeDoc = new DocumentMeta();            
   largeDoc.Guid = genDoc.Guid;            
   largeDoc.NumberOfPages = genDoc.NumberOfPages;                    
   largeDoc.ImportInfo = genDoc.ImportInfo;            
   largeDoc.Tag = genDoc.Tag;            
   largeDoc.Errors = genDoc.Errors;
   if(genDoc.Pages == null){
      Uri url = HttpContext.Current.Request.Url;
      string tempUri = url.AbsoluteUri.ToString();                
      tempUri = tempUri.Substring(0, tempUri.Length - 4);                    
      largeDoc.Uri = tempUri + "file";            
   }
   return largeDoc;        
}

SaveMetrics Method

Method definition:

public void SaveMetrics(Template template, Metrics metrics)

Input parameters:

  1.  Template template
    1. The template associated with this request.
  2. Metrics metrics
    1.  The generated metrics.

The SaveMetrics method saves a completed metrics request. You can save the metrics object however you want, as long as it is easily identifiable using its GUID. As an example, the default FileSystemRepository implemented in the RESTful engine serializes the errors as data contracts to files titled                                               " {template.guid}.metrics.complete".  Just make sure however you save it, you use the template's guid as an identifier (name of the file, id entry in database, etc.).


GetMetrics Method

Method definition:

public Metrics GetMetrics(string guid)

Input parameters:

  1.  guid
    1. The unique identifier for this request.

The GetMetrics method retrieves the metrics object associated with the passed GUID. Use the GUID input parameter as an identifier to find the metrics object however you chose to save it in the SaveMetrics method.

SaveTagTree Method

Method definition:

public void SaveTagTree(Template template, TagTree tagtree)

Input parameters:

  1.  Template template
    1. The template associated with this request.
  2. TagTree tagtree
    1.  The generated tagtree.

The SaveTagTree method saves a completed tagtree request. You can save the tagtree object however you want, as long as it is easily identifiable using its GUID. As an example, the default FileSystemRepository implemented in the RESTful engine serializes the errors as data contracts to files titled                                               " {template.guid}.tagtree.complete".  Just make sure however you save it, you use the template's guid as an identifier (name of the file, id entry in database, etc.).

GetTagTree Method

Method definition:

public Metrics GetTagTree(string guid)

Input parameters:

  1.  guid
    1. The unique identifier for this request.

The GetTagTree method retrieves the tagtree object associated with the passed GUID. Use the GUID input parameter as an identifier to find the tagtree object however you chose to save it in the SaveTagTree method.

DeleteReport Method

Method definition:

public void DeleteReport(string guid)

Input parameters:

  1.  guid
    1. The unique identifier for this request.

The DeleteReport method is used to delete a generated document from the repository using its guid as the identifier. If you are using our default job handler, we recommend you st up a delete queue, and using it as follows:

private ConcurrentQueue<string> queueDeletes;
.
.
.

public void DeleteReport(string guid){            
   queueDeletes.Enqueue(guid);            
   eventSignal.Set();        
}

Shutdown Method

Method definition:

void Shutdown()

The Shutdown method reverts all jobs in processing to pending (waiting to start). The web server is closing down. Here you will want to get any requests written to the disk and kill the worker thread. The way we have it implemented we would change all ".generate" files to ".pending" files in preparation for the server shutdown.

How to Use Defined Repository

Now that you have defined your repository, it is time to include it in your RESTful Engine installation. The first thing you need to do is compile your repository project into a dll.  Once you have the dll, you want to do the following in your RESTful engine's web.config:

<appSettings>
   <add key="repository" value="filename!classname" />
</appSetings>

Where:

  • filename is the path to your IRepository.dll implementation (if there are spaces in the path, put it in quotes)
  • classname is the full class name of your repository class:
    • ie. if your namespace is CustomRepository and your class is named Repository, classname would be CustomRepository.Repsoitory.

0 Comments

Add your comment

E-Mail me when someone replies to this comment

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.