You are browsing the archive for ASP.NET.

Profile photo of marc

by marc

Choosing the Best Toolchain for each Platform

February 4, 2012 in .NET, Android, ASP.NET, Cocoa, Data Abstract, Delphi, Elements, iOS, Java, JavaScript, Mac, Metro, Mono, MonoTouch, non-tech, Oxygene, Platforms, RemObjects, Visual Studio, Windows, Windows Phone, Xcode

Four or five years ago, the software world was simple: if you were a commercial software developer, you were developing for Windows. But this has changed drastically with the advent of mobile platforms such as iOS and Android, the steadily increasing market share of Macs, and the establishment of new development paradigms such as rich web applications hosted in browsers.

Here at RemObjects, I field the majority of so called “sales related” emails (that is, emails that aren’t technical support requests handled by our excellent support team and the product developers) myself — and as this century gets older, I see more and more requests asking what tools and toolchains to pick for different platforms. “Can I develop for both Windows Phone 7 and Android with Oxygene and share code?” — “Which version of Data Abstract is best for targeting iOS?” — “Should I use Oxygene for .NET with MonoDroid or Oxygene for Java for my Android app?”.

There are a lot of great development tool chains for the different platforms out there — be they Xcode/Cocoa, Visual Studio/.NET, Delphi, JavaScript — and sometimes the decision does not seem easy, because here at RemObjects we provide editions of most of our products for various development platforms, and often more than one choice can be applied to a specific platform need.

To help make heads and tails of this, we created a small graphical overview chart on our website that gives insight into which language/framework/product combinations we support on any given platform and — more importantly IMHO — which combination we recommend.*

[*And that recommendation might not always be what you think — for example, I often get looked at weirdly when I recommend Xcode over our own Oxygene (plus Mono) for Mac development. But development tools, even versatile ones such as Oxygene, or Delphi, or Visual Studio, are not and should not be Jacks of all Trades, and thus no single tool, no matter how great (and we happen to think Oxygene is pretty great ;) can be the best choice for all scenarios. We acknowledge and honor that.]

You can find this overview matrix — which will be ever-expanding as time goes by and the development world around us changes — at remobjects.com/products/toolchains; i’m also including a static screenshot of it, below.

May it help you to choose the best set of tools for your needs!



Profile photo of marc

by marc

Hydra 4 and Oxygene January 2012 Releases

February 1, 2012 in .NET, Android, ASP.NET, Cooper, Delphi, Elements, Hydra, Java, Oxygene, Visual Studio, Windows, Windows Phone

We’re hitting the ground running for 2012 and finished January with the first two product releases of the year.

Hydra 4

Hydra 4 is a major new release for our .NET/Delphi cross-platform product, and one we’re very excited about. Hydra has been at version 3 for a while now and seen mostly incremental changes, but with version 4 we’re adding three major new features/platforms to the mix:

  • Support for 64-bit Delphi Host Applications and Plugins
  • Support for FireMonkey Host Applications and Plugins
  • Support for hosting Silverlight-based Plugins

Compiling true 64-bit Windows applications has been on the wish-list for Delphi developers for a long time, and Delphi XE2 finally provided the elusive support, and Hydra has been updated to match. This makes it easier to build applications that use large amounts of memory, can interact with .NET plugins in 64-bit space, or simply run more natively on the 64-bit Windows systems that are standard these days.

FireMonkey is Embarcadero’s new framework for creating rich “HD” or 3D graphical user interfaces in Delphi, and it is destined to supersede the VCL sooner or later. Unfortunately, Embarcadero does not let applications mix FireMonkey (FMX) and VCL by default — but that is no reason to jump ship to FireMonkey and discard all your existing VCL code. Hydra adds FireMonkey to its list of platforms supported by plugins and lets you seamlessly mix new FireMonkey UI alongside existing VCL code or even among WinForms and WPF. And FireMonkey host support lets you create new FMX applications and integrate existing VCL (or WinForms and WPF) code and UI into them, as well.

Finally, there’s Silverlight, Microsoft’s platform for rich web controls and (more prominently, as of recent) Windows Phone 7. Silverlight is based on the same concepts as .NET but uses a smaller and a tad more limited runtime — in exchange it can run in Browsers on Windows and Mac, as well as on Microsoft’s new phone platform. With Hydra 4, Silverlight can now also run in your Delphi (or .NET) based host applications, alongside other plugins. This allows you to easily share code and visual elements between your web application and your desktop app, or between your phone and your desktop.

We think Hydra 4 will be an essential tool for the modern Delphi developer — whether to add .NET to your Delphi projects or to add FireMonkey.

Hydra 4 is a free update to all users with an active subscription and available for immediate download. If your subscription expired before January 27, you can renew now for $249 to get access to Hydra 4; the price for new users is $499, including on year of free updates (and we do have more exciting stuff planned for Hydra in 2012!). Of course Hydra 4 is also included in the Suite Subscriptions for both .NET and Delphi.

Oxygene — January 2012 Release

Last November, we shipped a major new release of Oxygene, introducing the brand new Oxygene for Java as second platform for everyone’s favorite modern Object Pascal.

After skipping the holidays, we’re back to our monthly release cycle, and the January 2012 release kicks the year off with a large range of fixes and enhancements for both .NET and Java/Android developers. Altogether, the change log contains over 170 improvements.

The new Oxygene build is a free update for all customers with an active subscription, including all users of Prism XE2 and RAD Studio XE2.

For those of you using Oxygene for both .NET and Java, the update (like all future updates) is a combined installer — it will automatically detect if you have both editions of Oxygene and update both.

Get Em While They’re Hot

Head over to our trials download page at remobjects.com/trials now to give Hydra 4 or Oxygene a spin. Or if you’re already a customer, visit the downloads page on your customer portal to get the latest versions.

Oxygene and Hydra go great together by the way. If you’re a Delphi-only developer right now but thinking about adding .NET code to your application, Hydra makes that easy, and Oxygene lets you keep using the familiar Object Pascal language, even for your .NET work.

Profile photo of Anton

by Anton

Data Abstract and ASP.NET MVC

October 4, 2011 in .NET, ASP.NET, Data Abstract, Platforms, Visual Studio

Introduction

Recently I’ve been asked if it is possible to use two exciting technologies – Data Abstract for .NET and ASP.NET MVC – together.

So I decided to write this little blogpost to show you how an ASP.NET MVC website is working with a Data Abstract-powered data provider. The created website will be really simple, without any fancy jQuery UI effects (they would be far beyond the scope of this article).

The created ASP.NET website will show a list of customers and the sample PC Trade database and it will retrieve data via a 2-tier Data Abstract-powered class library hidden behind an interface.

Data Source

Data Abstact Class Library

The first step is to create a data provider assembly. Create a new RemObjects Data Abstact Class Library project and name it, say, MvcSample.Backend.

Create a new 2-tier application that uses a PCTrade-SQLite datasource. Be sure to uncheck the ‘Add Server Channel to the project‘, ‘Add Login Service‘ and ‘Add support for Business Rules Scripting‘ options.

We will use DA LINQ Table Definitions and Model classes.

Rename the TableDefinitions_MvcSample.BackendDataset.cs file to MvcSample.Model.cs. Open it and correct the namespace from MvcSample.Backend.MvcSample.BackendDataset to MvcSample.Model, as well. Note that all classes defined in this file are partial, so you can easily add new properties and methods to them when needed.

Also rename the Customers class to Customer.

Note that these changes will be lost once you regenerate the TableDefinitions file, so in most cases, it is much better to rename the corresponding Schema Table instead.

At this point we can already use the MvcSample.Backend assembly as data source for the ASP.NET MVC application.

But let’s improve it by hiding all Data Abstract-specific details behind interfaces and static methods.

Data Access Engine startup

Let’s add a static Repository class with a single (for now) method:

using MvcSample.Backend;
 
namespace MvcSample.DataLayer
{
    public static class Repository
    {
        private static Engine engine;
 
        public static void Initialize()
        {
            if (Repository.engine == null)
                Repository.engine = new Engine();
        }
    }
}

We will call this method later in the Application_Start method of the Global.asax.cs file.

Data Access Interface

Now we need to add a data access interface and implement it. This approach may look over-complicated for this sample, but it will later allow to create a more testable application (you will, for example, be able to mock the data access interface in unit tests and test appliction logic agains data loaded from memory instead of the database). Another advantage of hiding all data access behind an interface is that the actual ASP.NET MVC application will be fully separated from the data access layer (as it should be).

The interface is:

using System;
using System.Collections.Generic;
using MvcSample.Model;
 
namespace MvcSample.DataLayer
{
    public interface IDataLayer
    {
        IList<Customer> GetAllCustomers();
 
        void CreateCustomer(Customer customer);
        void UpdateCustomer(Customer customer);
        Customer GetCustomer(String id);
        void DeleteCustomer(String id);
    }
}

It is implemented in the private DataLayer class:

using System;
using System.Collections.Generic;
using System.Linq;
using RemObjects.DataAbstract.Linq;
using MvcSample.Backend;
using MvcSample.Model;
 
namespace MvcSample.DataLayer
{
    class DataLayer : IDataLayer
    {
        private DataModule fDataModule;
        private LinqDataAdapter fDataAdapter;
 
        public DataLayer(DataModule dataModule)
        {
            this.fDataModule = dataModule;
            this.fDataAdapter = this.fDataModule.DataAdapter;
        }
 
        public IList<Customer> GetAllCustomers()
        {
            var query = from c
                        in this.fDataAdapter.GetTable<Customer>()
                        select c;
 
            return query.ToList<Customer>();
        }
 
        public void CreateCustomer(Customer customer)
        {
            this.fDataAdapter.GetTable<Customer>().InsertRow(customer);
            this.fDataAdapter.ApplyChanges();
        }
 
        public Customer GetCustomer(String id)
        {
            return (from c
                    in this.fDataAdapter.GetTable<Customer>()
                    where c.Id == id
                    select c).FirstOrDefault();
        }
 
        public void UpdateCustomer(Customer customer)
        {
            this.fDataAdapter.GetTable<Customer>().UpdateRow(customer);
            this.fDataAdapter.ApplyChanges();
        }
 
        public void DeleteCustomer(String id)
        {
            this.fDataAdapter.GetTable<Customer>().DeleteRow(new Customer() { Id = id });
            this.fDataAdapter.ApplyChanges();
        }
    }
}

To provide access to the data layer, we need to add this method to the Repository class:

public static IDataLayer GetDataLayer()
{
    DataModule module = new DataModule();
    // In more advanced scenarios, one could use an ObjectPool
    // to provide a pool of data modules instead of
    // instantiating a new data module for each request.
 
    return new DataLayer(module);
}

At this point we have the data access layer and the model classes. Now the fun part begins – the ASP.NET MVC application.

ASP.NET MVC Web Site

Add a new ASP.NET MVC 3 project to the solution and name it MvcSample.Web. In the project properties select an ‘Empty’ project template and the Razor view engine and enable HTML5 markup.

Set the MvcSample.Web project as StartUp one and add the MvcSample.Backend project to its references.

Build the solution (so the ASP.NET MVC helpers will know about our model classes). I won’t use all the advanced ASP.NET MVC helpers stuff like staffolding etc. and will create the application by myself, step-by-step.

Now we need to add a controller. We need an empty controller named CustomersController.

Right-click on the ‘Controllers’ folder of your ASP.NET MVC project and select the ‘Add…’ -> ‘Controller’ menu item.

The controller class implementation is really simple (for now):

using System;
using System.Collections.Generic;
using System.Web.Mvc;
using MvcSample.DataLayer;
using MvcSample.Model;
 
namespace MvcSample.Web.Controllers
{
    public class CustomersController : Controller
    {
        //
        // GET: /Customers/
        // GET: /Customers/Index/
        public ActionResult Index()
        {
            IList<Customer> data = Repository.GetDataLayer().GetAllCustomers();
            return this.View(data);
        }
    }
}

Now we need to create a view for this action. Right-click on the method source code and select the ‘Add View…’ menu item.

The next step is to add a view that will list Customers. Unfortunately, Visual Studio refuses to create a strongly-typed view for me automatically. So I created an empty view and added all the needed Razor code:


@model IEnumerable<MvcSample.Model.Customer>
@{
    ViewBag.Title = "Index";
}
<h2>
    Index</h2>
<p>@ViewBag.Message</p>
<p>@Html.ActionLink("Create New", "Create")</p>
<table>
    <tr>
        <th>
            Name
        </th>
        <th>
            Phone
        </th>
        <th>
            Address
        </th>
        <th>
        </th>
    </tr>
    @foreach (var item in Model)
    {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.Name)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Phone)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Address)
            </td>
            <td>
                @Html.ActionLink("Edit", "Edit", new { id = item.Id }) |
                @Html.ActionLink("Details", "Details", new { id = item.Id }) |
                @Html.ActionLink("Delete", "Delete", new { id = item.Id })
            </td>
        </tr>
    }
</table>

It is really annoyng that ASP.NET MVC failed to create a dummy view for me. But considering that these views are usually thrown away anyway (because all the jQuery stuff requires way more advanced View code to be created), this is not really a huge problem.

Unfortunately, if you start the MVC application now, it will fail with an exception because we forgot to register the Customer route. Open the Global.asax.cs file and and correct the RegisterRoute method:

public static void RegisterRoutes(RouteCollection routes)
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
 
    routes.MapRoute(
        "Default", // Route name
        "{controller}/{action}/{id}", // URL with parameters
        new { controller = "Customers", action = "Index", id = UrlParameter.Optional } // Parameter defaults
    );
}

Also don’t forget to initialize the Data Abstract infrastructure:

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();
 
    RegisterGlobalFilters(GlobalFilters.Filters);
    RegisterRoutes(RouteTable.Routes);
 
    MvcSample.DataLayer.Repository.Initialize();
}

Now hit F5 and run the app. And it will fail again.

Data Abstract is not able to load the .daConnectionFile because the Assembly.GetEntryAssembly() method used to determine the name of the .daConnections resource returns
null for ASP.NET applications. We have to change the way connections are loaded in the Engine constructor:

public Engine()
{
    this.InitializeComponent();
 
    if (!RemObjects.DataAbstract.Server.Configuration.Loaded)
        RemObjects.DataAbstract.Server.Configuration.Load();
 
    XmlDocument lConnectionsXml = new XmlDocument();
    lConnectionsXml.Load(typeof(Engine).Assembly.GetManifestResourceStream(typeof(Engine).Assembly.GetName().Name + ".MvcSample.Backend.daConnections"));
    this.connectionManager.LoadFromXml(lConnectionsXml);
}

After this change, run the ASP.NET MVC application again and it will show a list of Customers:

And, as if this was not enough, look at this screenshot:

It took no more than 5 minutes to add all the code needed to provide a simple editor and a details view for customer. The controller class now looks like this:

using System;
using System.Collections.Generic;
using System.Web.Mvc;
using MvcSample.DataLayer;
using MvcSample.Model;
 
namespace MvcSample.Web.Controllers
{
    public class CustomersController : Controller
    {
        //
        // GET: /Customers/
        // GET: /Customers/Index/
        public ActionResult Index()
        {
            IList<Customer> data = Repository.GetDataLayer().GetAllCustomers();
            return this.View(data);
        }
 
        public ActionResult Details(String id)
        {
            Customer customer = Repository.GetDataLayer().GetCustomer(id);
 
            return this.View(customer);
        }
 
        public ActionResult Edit(String id)
        {
            Customer customer = Repository.GetDataLayer().GetCustomer(id);
 
            return this.View(customer);
        }
 
        [HttpPost]
        public ActionResult Edit(Customer customer)
        {
            Repository.GetDataLayer().UpdateCustomer(customer);
 
            return this.RedirectToAction("Index");
        }
    }
}

and Detail and Edit views are corespondingly:

@model MvcSample.Model.Customer

@{
    ViewBag.Title = "Details";
}

<h2>Details</h2>

<fieldset>
    <legend>Customer</legend>

    <div class="display-label">Name</div>
    <div class="display-field">
        @Html.DisplayFor(model => model.Name)
    </div>

    <div class="display-label">Phone</div>
    <div class="display-field">
        @Html.DisplayFor(model => model.Phone)
    </div>

    <div class="display-label">Address</div>
    <div class="display-field">
        @Html.DisplayFor(model => model.Address)
    </div>
</fieldset>
<p>
    @Html.ActionLink("Edit", "Edit", new { id=Model.Id }) |
    @Html.ActionLink("Back to List", "Index")
</p>

and

@model MvcSample.Model.Customer

@{
    ViewBag.Title = "Edit";
}

<h2>Edit</h2>

<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>

@using (Html.BeginForm()) {
    @Html.ValidationSummary(true)
    <fieldset>
        <legend>BookDetails</legend>

        @Html.HiddenFor(model => model.Id)

        <div class="editor-label">
            @Html.LabelFor(model => model.Name)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Name)
            @Html.ValidationMessageFor(model => model.Name)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.Phone)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Phone)
            @Html.ValidationMessageFor(model => model.Phone)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.Address)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Address)
            @Html.ValidationMessageFor(model => model.Address)
        </div>

        <p>
            <input type="submit" value="Save" />
        </p>
    </fieldset>
}

<div>
    @Html.ActionLink("Back to List", "Index")
</div>

Conclusion

We have created a simple ASP.NET MVC application that gets its data via Data Abstract. Only minimal changes were needed in the Data Abstract access class library, caused by the ASP.NET specifics.
The ASP.NET MVC code is not even aware of its data source, because all Data Abstract specifics are hidden behind a simple interface.