Additional Datasources

Topics: Feature requests, General, MVC
May 22, 2012 at 12:38 AM

Hi,

I just stated evaluating Composite C1 today and I'm quite impressed. I'd like to know if I can add a Firebird Sql 2.5 data source to a project. I've used Firebird with Entity Framework 4.3.1 with MVC3 and MVC4 and this would be a great addition for both my projects and the to the Firebird community. 

TIA

John

May 22, 2012 at 1:23 AM

If you want to completely replace the existing XML and SQL Server support with Firebird SQL you would need to implement a data provider (implementing IGeneratedTypesDataProvider, ILocalizedDataProvider). The xml and sql server based providers are using LINQ for XML and LINQ for SQL so there would need to be something similar for Firebird SQL for this to be feasible.

Building a dynamic (able to create new data schema on the fly) data provider like xml/sql is not trivial, and if you are just looking for ways to pull in data from Firebird SQL through the LINQ based data layer in Composite C1 you can do one of these:

  • A read/write (non dynamic) data provider - implement IWritableDataProvider
  • A read only data provider - implement IDataProvider

See http://docs.composite.net/Data/CustomDataProviders

If your goal is simply to have functionality on pages which work with Firebird SQL data and you write this using .net (using Razor Functions, MVC Player or User Control Functions) you can keep on using Entity Framework as usual - this will work just fine.

If you are looking for ways to expose data from Firebird as XML so an XSLT dev can work with it, look into creating C# Functions that return XElements.

Let me know what level of integration you want and I'll go more in depth in that direction :)

 

May 22, 2012 at 2:00 AM
Hi,
No need to replace the infrastructure with Firebird, I just want the ability to get the data for CRUD and possibly use 3rd party controls from DevExpress. If there was a EF provider wouldn't that handle all providers available to EF? Thanks for your prompt reply and I will spend some time tomorrow with your documents and get back to you. I also have created XML from FB so I can explore that later. I'm also looking to get certified as I see opportunity in this space.
Thanks,
John
May 24, 2012 at 5:34 PM

Hi,

I've successfully developed an EF 4.X with Firebird 2.5, mvc 3 with razor view and Composite. I'd like to blog about it (http://johntomaselli.blogspot.com/) but first want your comments on how I accomplished the first task and your feedback on the failed second task.

Task1

1) Use CompositeC1WebProject_3.2.4497.34793.zip as base

2) Create the following folders; App_code\Controllers; ; App_code\Models; Views\Blog; Views\Scripts; Views\Content

3) Create edmx model in \Models with ADO.Net Entity Data Model template

4) Create classes with ADO.Net DbContext Generator (must install EF 4.1 for templates)

5) Copy previously created mvc view and controller from a project using same model

6) Copy all javascript libraries to Views\Scripts folder

7) From Composite admin install composite mvc player

8) add a new page to Front page

9) add a new function with path=/Blog

10) save, publish and open website.

11) I can now add, edit and delete blog entries from new page. Nice!

Task2 more advanced.

1) Follow same steps but use a view with DexExpress mvc grid.

2) Create \Views\Shared folder and copy _Layout.cshtml (see attached)

3) Copy controller and view from a previous project along with \Views\ _ViewStart.cshtml

@{

Layout = "~/Views/Shared/_Layout.cshtml";

}

4) add a new page to Front page

5) add a new function with path=/Invoices

6) save, publish and open website.

7) A error appears with opening page and also prevents from the working page above to display. See attached GridViewPartial.cshtml and error.txt

Is this possible?

Thanks,

John

May 24, 2012 at 8:11 PM

Hi,

Found some missing entries in the web.config and now get the following error.

John

System.InvalidOperationException was unhandled by user code

Message=MvcPlayer: failed to parse result markup as xml

Source=App_Code.qexxzanj

StackTrace:

at Composite.AspNet.MvcPlayer.Functions.RenderInternal(String path) in c:\VisualStudio2010\MVC3\CompositeC1WebProjectBaseMVCTest\Website\App_Code\Composite\AspNet\MvcPlayer\Player.cs:line 129

at Composite.AspNet.MvcPlayer.Functions.Render(String Path) in c:\VisualStudio2010\MVC3\CompositeC1WebProjectBaseMVCTest\Website\App_Code\Composite\AspNet\MvcPlayer\Player.cs:line 59

InnerException: System.Xml.XmlException

Message=Unexpected DTD declaration. Line 4, position 3.

Source=System.Xml

LineNumber=4

LinePosition=3

SourceUri=""

StackTrace:

at System.Xml.XmlTextReaderImpl.Throw(Exception e)

at System.Xml.XmlTextReaderImpl.Throw(String res, String arg)

at System.Xml.XmlTextReaderImpl.ParseElementContent()

at System.Xml.XmlTextReaderImpl.Read()

at System.Xml.Linq.XContainer.ReadContentFrom(XmlReader r)

at System.Xml.Linq.XContainer.ReadContentFrom(XmlReader r, LoadOptions o)

at System.Xml.Linq.XDocument.Load(XmlReader reader, LoadOptions options)

at System.Xml.Linq.XDocument.Parse(String text, LoadOptions options)

at System.Xml.Linq.XDocument.Parse(String text)

at Composite.AspNet.MvcPlayer.Functions.RenderInternal(String path) in c:\VisualStudio2010\MVC3\CompositeC1WebProjectBaseMVCTest\Website\App_Code\Composite\AspNet\MvcPlayer\Player.cs:line 125

InnerException:

May 24, 2012 at 9:09 PM
Edited May 24, 2012 at 9:14 PM

Looks like the view outputs a DTD declaration like<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

Try to check the view for this and remove it.

May 24, 2012 at 10:09 PM

Hi,

I removed it but still get the following.

John

May 24, 2012 at 10:11 PM
Edited May 24, 2012 at 10:16 PM

Can you post the view?

And are you still getting the "Unexpected DTD declaration" message?

May 24, 2012 at 10:38 PM

Hi,

I know how difficult this can be and will send anything you want to see if it can be resolved as I use DevExpress components for most of my projects.

That said I'm open to other solutions as I readily see the benefits of CompositeC1.

Thanks,

John

From: mawtex [email removed]
Sent: Thursday, May 24, 2012 5:12 PM
To: John R. Tomaselli
Subject: Re: Additional Datasources [CompositeC1:356614]

From: mawtex

Can you post the view?

May 24, 2012 at 10:45 PM

if is because your mvc-view doesn't return valid xhtml, one option could be to rewrite the MvcPlayer as a UserControl function. These don't have the same explicit restriction, but you loose the ability to pass the returned value from your MVC view as a parameter to another function. But since its not valid xhtml anyway, you wouldn't be able to do it anyway, so IMO that would be your best option.

I should be able to do a version of the MvcPayer as UserControl function tomorrow and post it here.

May 24, 2012 at 10:48 PM

You can also try to set a break point in the MVC Player code (you find it below ~/App_Code) and examine what markup come out from executing your MVC bits.

The markup needs to be "propper xml" so it will fit inside an xhtml document. This is the reason your DTD declaration made the MVC Player hickup - when it tries to merge your result into the final xhtml document, the DTD declaration create an invalid document.

Besude from the DTD thing, look for other elements which violate the laws of xml - stand alone elements must be ended like <br />, properties are "in quotes", characters like & and < needs to be encoded and you should stick to numeric entities (i.e. &#169; instead of &copy;).

If you make a break point, debug and then grab the generated markup you should be able to see than the issue is. Also, the message in the exception should give a good indication of what is creating problems.

I hope this helps - I'm looking forward to read your blog post!

May 24, 2012 at 11:37 PM

Hi

1) The -0002.png is what the view looks like when working. Grouping, Filtering etc and all very useful.

2) Dump has the value grabbed from player.cs

3) Certainly does not look like standard xml

4) I'll wait for a alternative as this is a bit deep.

Thanks for all your efforts,

John

From: mawtex [email removed]
Sent: Thursday, May 24, 2012 5:48 PM
To: John R. Tomaselli
Subject: Re: Additional Datasources [CompositeC1:356614]

From: mawtex

You can also try to set a break point in the MVC Player code (you find it below ~/App_Code) and examine what markup come out from executing your MVC bits.

The markup needs to be "propper xml" so it will fit inside an xhtml document. This is the reason your DTD declaration made the MVC Player hickup - when it tries to merge your result into the final xhtml document, the DTD declaration create an invalid document.

Besude from the DTD thing, look for other elements which violate the laws of xml - stand alone elements must be ended like
, properties are "in quotes", characters like & and < needs to be encoded and you should stick to numeric entities (i.e. © instead of ©).

If you make a break point, debug and then grab the generated markup you should be able to see than the issue is. Also, the message in the exception should give a good indication of what is creating problems.

I hope this helps - I'm looking forward to read your blog post!

May 30, 2012 at 12:00 PM
Edited May 30, 2012 at 12:21 PM

Sorry for my late reply! So, what i've done is i've refactored the MvcPlayer so it can play and return either string or XDocument. Its all pretty simple, this is what the refactored class looks like.

public static class MvcPlayer
    {
        public static string Play(string path)
        {
            var result = playInternal(path);

            return result;
        }

        public static XDocument XPlay(string path)
        {
            var result = Play(path);
            if (result == null)
            {
                return new XDocument();
            }

            var sbHtml = new StringBuilder();
            sbHtml
                .Append(@"<html xmlns=""http://www.w3.org/1999/xhtml""> 
                <head/>
                <body>")
                .Append(result)
                .Append(@"
                </body>
                </html>");

            try
            {
                return XDocument.Parse(sbHtml.ToString());
            }
            catch (Exception ex)
            {
                throw new InvalidOperationException("MvcPlayer: failed to parse result markup as xml", ex);
            }
        }

        private static string PathInfo
        {
            get
            {
                var pathInfo = C1PageRoute.GetPathInfo();
                if (pathInfo != String.Empty)
                {
                    C1PageRoute.RegisterPathInfoUsage();
                }

                return pathInfo;
            }
        }        

        private static string playInternal(string path)
        {
            var ctx = HttpContext.Current;
            var response = ctx.Response;

            if (!String.IsNullOrEmpty(PathInfo))
            {
                path = PathInfo;
            }

            Guid pageId = PageRenderer.CurrentPageId;

            using (var responseWriter = new StringWriter())
            {
                var httpResponceBase = new MvcPlayerHttpResponseWrapper(new HttpResponse(responseWriter), pageId);
                var httpContext = new MvcPlayerHttpContextWrapper(ctx, httpResponceBase);

                ProcessRequest(httpContext, path);

                // Redirects
                if (!String.IsNullOrEmpty(httpResponceBase.RedirectLocation))
                {
                    response.Redirect(httpResponceBase.RedirectLocation, false);
                    response.Flush();
                    response.Close();

                    return null;
                }

                // Ajax requests
                if (httpContext.Request.IsAjaxRequest())
                {
                    byte[] bytes = response.ContentEncoding.GetBytes(responseWriter.ToString());
                    response.Buffer = true;
                    response.ClearContent();
                    response.ClearHeaders();
                    response.ContentType = httpResponceBase.ContentType;
                    response.AddHeader("Content-Length", bytes.Length.ToString());
                    response.AddHeader("Content-Encoding", "none");
                    response.BinaryWrite(bytes);
                    response.Flush();
                    response.Close();

                    return null;
                }

                return responseWriter.ToString();
            }
        }

        private static void ProcessRequest(HttpContextWrapper httpContext, string path)
        {
            httpContext.RewritePath(String.Format("~/{0}", path));

            var handler = new MvcHttpHandlerWrapper();
            handler.ProcessRequest(httpContext);
        }

So now, we can create a UserControl which looks like this, and be able to return invalid xhtml from the player, without C1 crashing

public class MvcPlayer : UserControl
    {
        public string Path { get; set; }

        protected override void Render(HtmlTextWriter writer)
        {
            var result = CompositeC1Contrib.MvcPlayer.MvcPlayer.Play(Path);
            if (result != null)
            {
                writer.Write(result);
            }
        }
    }
May 31, 2012 at 8:41 PM

Thanks so much for your reply and I will get back to you asap. Also like to note that I got it working with ComponentOne Wijmo components for mvc.

John

From: burningice [email removed]
Sent: Wednesday, May 30, 2012 7:00 AM
To: John R. Tomaselli
Subject: Re: Additional Datasources [CompositeC1:356614]

From: burningice

Sorry for my late reply! So, what i've done is i've refactored the MvcPlayer so it can play and return either string or XDocument. Its all pretty simple, this is what the refactored class looks like.

public static class MvcPlayer
    {
        public static string Play(string path)
        {
            var result = RenderInternal(path);
 
            return result;
        }
 
        public static XDocument XPlay(string path)
        {
            var result = Play(path);
            if (result == null)
            {
                return new XDocument();
            }
 
            var sbHtml = new StringBuilder();
            sbHtml
                .Append(@"<html xmlns=""http://www.w3.org/1999/xhtml""> 
                <head/>
                <body>")
                .Append(result)
                .Append(@"
                </body>
                </html>");
 
            try
            {
                return XDocument.Parse(sbHtml.ToString());
            }
            catch (Exception ex)
            {
                throw new InvalidOperationException("MvcPlayer: failed to parse result markup as xml", ex);
            }
        }
 
        private static string PathInfo
        {
            get
            {
                var pathInfo = C1PageRoute.GetPathInfo();
                if (pathInfo != String.Empty)
                {
                    C1PageRoute.RegisterPathInfoUsage();
                }
 
                return pathInfo;
            }
        }        
 
        private static string RenderInternal(string path)
        {
            var ctx = HttpContext.Current;
            var response = ctx.Response;
 
            if (!String.IsNullOrEmpty(PathInfo))
            {
                path = PathInfo;
            }
 
            Guid pageId = PageRenderer.CurrentPageId;
 
            using (var responseWriter = new StringWriter())
            {
                var httpResponceBase = new MvcPlayerHttpResponseWrapper(new HttpResponse(responseWriter), pageId);
                var httpContext = new MvcPlayerHttpContextWrapper(ctx, httpResponceBase);
 
                ProcessRequest(httpContext, path);
 
                // Redirects
                if (!String.IsNullOrEmpty(httpResponceBase.RedirectLocation))
                {
                    response.Redirect(httpResponceBase.RedirectLocation, false);
                    response.Flush();
                    response.Close();
 
                    return null;
                }
 
                // Ajax requests
                if (httpContext.Request.IsAjaxRequest())
                {
                    byte[] bytes = response.ContentEncoding.GetBytes(responseWriter.ToString());
                    response.Buffer = true;
                    response.ClearContent();
                    response.ClearHeaders();
                    response.ContentType = httpResponceBase.ContentType;
                    response.AddHeader("Content-Length", bytes.Length.ToString());
                    response.AddHeader("Content-Encoding", "none");
                    response.BinaryWrite(bytes);
                    response.Flush();
                    response.Close();
 
                    return null;
                }
 
                return responseWriter.ToString();
            }
        }
 
        public static void ProcessRequest(HttpContextWrapper httpContext, string path)
        {
            httpContext.RewritePath(String.Format("~/{0}", path));
 
            var handler = new MvcHttpHandlerWrapper();
            handler.ProcessRequest(httpContext);
        }

So now, we can create a UserControl which looks like this, and be able to return invalid xhtml from the player, without C1 crashing

public class MvcPlayer : UserControl
    {
        public string Path { get; set; }
 
        protected override void Render(HtmlTextWriter writer)
        {
            var result = CompositeC1Contrib.MvcPlayer.MvcPlayer.Play(Path);
            if (result != null)
            {
                writer.Write(result);
            }
        }
    }
 
 
May 31, 2012 at 10:19 PM

Hi,

I've tried to apply the code sent in the player.cs but get missing reference messages. Could you send the file?

Thanks,

John

 
Feb 28, 2013 at 5:45 PM
johntom


I haven't used it, but Kellerman Software has a LINQ provider for Firebird
https://www.kellermansoftware.com/p-47-net-data-access-layer.aspx
Feb 28, 2013 at 5:51 PM
mawtex


I haven't used it, but Kellerman Software has a LINQ provider for Firebird
https://www.kellermansoftware.com/p-47-net-data-access-layer.aspx