开发者

How to make this code DRY?

I'm writing RESTful service with C#/wcf 开发者_C百科and need to put filters on GET. Like how many records to return, maybe if I want to filter by something, etc. Consider this code:

[WebGet(UriTemplate = "/devices/{DeviceId}/positions")]
        public List<GPSPosition> GetDevicePositions(string deviceId)
        {
            //Lookup device:
            using (var context = new MobileModelContext(ContextManager.AccountGKey.Value))
            {
                var d = context.Devices.Where(aa => aa.DeviceId == deviceId).FirstOrDefault();
                if (d == null)
                {
                    outgoingResponse.StatusCode = HttpStatusCode.NotFound;
                    outgoingResponse.StatusDescription = "Device not found";
                    return null;
                }

                var query = from p in context.Positions
                            where p.DeviceKey.Equals(d.DeviceKey)
                            select new GPSPosition
                            {
                                PositionGKey = p.PositionGKey,
                                Latitude = p.Latitude,
                                Longitude = p.Longitude,
                                Speed = p.Speed,
                                Accuracy = p.Accuracy,
                                Altitude = p.Altitude,
                                GPSTime = p.GPSTime,
                                DeviceTime = p.DeviceTime
                            };

                return query.ToList();
            }
        }

        [WebGet(UriTemplate = "/devices/{DeviceId}/positions?RecordCount={RecordCount}")]
        public List<GPSPosition> GetDevicePositions2(string deviceId, int recordCount)
        {
            //Lookup device:
            using (var context = new MobileModelContext(ContextManager.AccountGKey.Value))
            {
                var d = context.Devices.Where(aa => aa.DeviceId == deviceId).FirstOrDefault();
                if (d == null)
                {
                    outgoingResponse.StatusCode = HttpStatusCode.NotFound;
                    outgoingResponse.StatusDescription = "Device not found";
                    return null;
                }

                var query = from p in context.Positions
                            where p.DeviceKey.Equals(d.DeviceKey)
                            select new GPSPosition
                            {
                                PositionGKey = p.PositionGKey,
                                Latitude = p.Latitude,
                                Longitude = p.Longitude,
                                Speed = p.Speed,
                                Accuracy = p.Accuracy,
                                Altitude = p.Altitude,
                                GPSTime = p.GPSTime,
                                DeviceTime = p.DeviceTime
                            };

                return query.Take(recordCount).ToList();
            }
        }

Lot of repetition. I can move code into other function but still, I have 2 templates, I have 2 functions. Is there any way to make 1 template for /positions/ that will cover all possible "?" scenarios?


Take enumerates source and yields elements until count elements have been yielded or source contains no more elements.

Since Take(n) returns at a maximum n items, but less if there are less available you can rewrite:

  public List<GPSPosition> GetDevicePositions(string deviceId)
  {
    return GetDevicePositions2(deviceId, int.MaxValue)
  }

which will then return all items.


QA Hint: context.Devices.Where(aa => aa.DeviceId == deviceId).FirstOrDefault(); can be shorten to context.Devices.Find(deviceId);

QA Hint: from p in context.Positions ... you may want to create a view on your table and instead of ... select new GPSPosition { ... } you would simply write regular context.PositionViews.Where(x => x.DeviceKey == d.DeviceKey).ToList();

QA Hint: You may want to use .AsNoTracking() to optimize performance.

QA Hint: You may want to use optional parameters in your method declarations. For example:

public List<GPSPosition> GetDevicePositions(string deviceId, int limit = 20)
{
// you code here
}

Or if WCF doesn't support it just yet. Here is a work-around:

You can get the desired effect by omitting the Query string from the UriTemplate on your WebGet or WebInvoke attribute, and using WebOperationContext.Current.IncomingRequest.UriTemplateMatch.QueryParameters from within your handlers to inspect, set defaults, etc. on the query parameters.

https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=451296&wa=wsignin1.0

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜